perm filename IL.TVR[UP,DOC]4 blob
sn#167918 filedate 1975-07-05 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00180 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00016 00002 UCI LISP MANUAL
C00017 00003 Table of Contents
C00021 00004 The LISP Editor 2. 1
C00025 00005 Extensions to the Standard Input/Output Functions 4. 1
C00029 00006 Functions for the System Builder 8. 1
C00031 00007 INTRODUCTION
C00035 00008 b) A powerful list structure editor for editing
C00039 00009 As mentioned, we have made UCI LISP a reentrant system
C00044 00010 allowing the user to perform whatever investigations he
C00049 00011 The editor is a very large, complicated function, and its
C00054 00012 The error protection facilities are an attempt to catch
C00057 00013 Credits and Acknowledgements
C00062 00014 for their aid in obtaining and explaining this material,
C00064 00015 1.1 DEBUGGING FACILITIES
C00069 00016 goes on with the computation. When an error occurs on the
C00073 00017
C00075 00018
C00077 00019 Interrupting a computation-REE and DDT
C00081 00020 4. Control-E: This does an (ERR NIL), which return NIL to
C00082 00021 BREAK1
C00087 00022 BRKWHEN returns NIL, BRKEXP is evaluated and returned as the
C00091 00023 WHAT YOU CAN DO IN A BREAK
C00095 00024 wishes to be able to do something about it if it is
C00098 00025 1.10 USE x FOR y
C00100 00026 Context Commands
C00104 00027 ←
C00108 00028 EDIT arg1 arg2 ... argN
C00112 00029 will print the name and value of the second
C00115 00030 Backtrace Commands
C00118 00031 The output of the backtrace commands deserves some
C00120 00032 Breakmacros
C00124 00033 BREAK PACKAGE
C00128 00034 (BREAK ((FOO4 IN FOO5) (MINUSP X)))
C00131 00035 1.20 BREAKIN
C00136 00036 ((FOO (AFTER COND 2 1)) BROKEN).
C00140 00037 broken (i.e. all those on BROKENFNS).
C00142 00038 BREAK0 [FN WHEN COMS]
C00146 00039 ERROR PACKAGE
C00151 00040 Table I
C00154 00041 the trace to that number of blocks. For example, BK 3,
C00155 00042
C00156 00043 2.1 The LISP Editor
C00160 00044 Introduction
C00163 00045 A positive integer is interpreted by the editor as a
C00167 00046 is used to ascend the chain it removes the last link of the
C00171 00047 The basic structure modification commands in the editor
C00175 00048 #P
C00179 00049 #P
C00182 00050 currently looking at (CAR X) in (CONS (CAR X) (APPEND (CDR X
C00186 00051 The E command causes the next input to be given to
C00187 00052 2.10 Commands for the New User
C00191 00053 <P
C00195 00054 @ (at-sign)
C00198 00055 UP
C00202 00056 (: e1,...,em)
C00205 00057 Attention Changing Commands
C00207 00058 Local Attention-Changing Commands
C00211 00059 because the commands that descend save the last tail on an
C00216 00060 0
C00219 00061 NX
C00223 00062 2.20 !NX
C00226 00063 #F CAR P
C00228 00064 Commands That Search
C00233 00065 will match with the element (A B C) as well as with CDR of
C00234 00066 Search Algorithm
C00239 00067 fails the edit chain is not changed (nor are any CONSes
C00241 00068 Search Commands
C00244 00069 (F pattern T)
C00248 00070 (FS pattern[1] ... pattern[n])
C00253 00071 (BF pattern T)
C00255 00072 2.30 Lob∂tion Specification
C00259 00073 (LC . $)
C00262 00074 (← pattern)
C00266 00075 (BELOW com)
C00270 00076 (NTH $)
C00274 00077 contains a RETURN that contains a COND.
C00275 00078 Commands That Save and Restore the Edit Chain
C00279 00079 <P
C00282 00080 Commands That Modify Structure
C00286 00081 Implementation of Structure Modification Commands
C00291 00082 2.40 current expression and FOO are now (A C D). (A general
C00294 00083 The A,B,: Commands
C00298 00084 higher expression by NIL. For example, if the current
C00300 00085 The following forms of the A, B, and : commands
C00304 00086 the tail, (C), will have been cut
C00308 00087 Form Oriented Editing and the Role of UP
C00313 00088 Extract and Embed
C00317 00089 The extract command can also incorporate a location
C00319 00090 While extracting replaces the current expression by a
C00322 00091 (EMBED $ IN . x)
C00324 00092 2.50 The MOVE Command
C00327 00093 As the following examples taken from actual editing
C00329 00094 Similarly, in the next example, in the course of specifying
C00332 00095 #(MOVE TO BEFORE LOOP)
C00333 00096 Commands That "Move Parentheses"
C00337 00097 (BO n)
C00341 00098 (RO n)
C00343 00099 TO and THRU
C00347 00100 of 6. This is because the $2 is located after $1 is. The
C00350 00101 ($1 TO), ($1 THRU)
C00353 00102 2.60 (R x y)
C00357 00103 (SW n m)
C00359 00104 Commands That Print
C00362 00105 Commands That Evaluate
C00366 00106 first element by the value of FOO.
C00370 00107 (COMS (CONS (QUOTE COMSQ) (GET FOO (QUOTE COMMANDS)))).
C00371 00108 Commands That Test
C00375 00109 When an error occurs, LP prints n
C00379 00110 Macros
C00383 00111 (M (c) args . coms)
C00388 00112 2.70 solves both problems.
C00391 00113 Miscellaneous Commands
C00395 00114 STOP
C00398 00115 SAVE is necessary only if the user is editing many
C00401 00116 REPACK
C00403 00117 2.75 (MAKEFN form args n m)
C00405 00118 UNDO
C00410 00119 similarly prevent an UNDO command from operating on commands
C00413 00120 Editdefault
C00416 00121 #P
C00417 00122 2.80 Editor Functions
C00422 00123 the edit. Thus SAVE will not save
C00425 00124 (EDITV editvx)
C00428 00125 (EDITFNS x)
C00432 00126 (EDITFPAT pat flg)
C00436 00127 3.1 EXTENDED INTERPRETATION OF LISP FORMS
C00439 00128 The Functions PROG1 and PROGN
C00440 00129 Conditional Evaluation of Forms
C00443 00130 Changes to the Handling of Errors
C00446 00131 Miscellania
C00448 00132 4.1 EXTENSIONS TO THE STANDARD INPUT/OUTPUT FUNCTIONS
C00451 00133 Printing Circular or Deeply Nested Lists
C00454 00134 "Pretty Printing" Function Definitions and S-Expressions
C00458 00135 Reading Whole Lines
C00460 00136 Teletype and Prompt Character Control Functions
C00463 00137 (READP)
C00464 00138
C00468 00139 Using Read Macros
C00470 00140 Modifying the READ Control Table
C00472 00141 5.1 NEW FUNCTIONS ON S-EXPRESSIONS
C00476 00142 *(SETQ FOO (NCONS NIL))
C00479 00143 S-Expression Transforming Functions
C00481 00144 S-Expression Modifying Functions
C00484 00145 Mapping Functions with Several Arguments
C00486 00146 Mapping Functions Which Use NCONC
C00489 00147 S-Expression Searching and Substitution Functions
C00491 00148 (LDIFF X Y)
C00493 00149 Efficiently Working with Atoms as Character Strings
C00495 00150 6.1 NEW PREDICATES
C00497 00151 Alphabetic Ordering Predicate
C00499 00152 Predicates that Return Useful Non-NIL Values
C00502 00153 Other Predicates
C00503 00154 7.1 NEW NUMERIC FUNCTIONS
C00504 00155 FORTRAN Functions in LISP
C00507 00156 8.1 FUNCTIONS FOR THE SYSTEM BUILDER
C00510 00157 (SETSYS DEVICE FILE)
C00512 00158 The Compiler and LAP
C00515 00159 Miscellaneous Useful Functions
C00518 00160 Initial System Generation
C00520 00161 4) To Generate COMPLR.SAV, The LISP COMPILER
C00522 00162 9.1 THE LISP EVALUATION CONTEXT STACK
C00525 00163 Examining the Context Stack
C00528 00164 (STKNAME P)
C00531 00165 Controlling Evaluation Context
C00534 00166 10.1 Storage Allocation
C00537 00167 Initial Allocations
C00538 00168 INDEX
C00543 00169 DSUBST ---------------------------------------- 5. 4
C00548 00170 LAPLST ---------------------------------------- 8. 2
C00553 00171 P (edit command) ------------------------------ 2. 2, 62
C00558 00172 TAN ------------------------------------------- 7. 2
C00563 00173 <P (edit command) ----------------------------- 2.11, 37
C00565 00174
C00566 00175 CHANGES TO THE UCILSP SYSTEM 9/73
C00569 00176 Changes to Old Functions
C00571 00177 New I/O Functions
C00573 00178 New Predicates
C00574 00179 Miscellaneous Functions
C00576 00180 BLOCK Data Type
C00578 ENDMK
C⊗;
UCI LISP MANUAL
by
Robert J. Bobrow
Richard R. Burton
Daryle Lewis
Table of Contents
Introduction 0. 0
Debugging Facilities 1. 1
Introduction 1. 1
Temporarily Interrupting a Computation 1. 5
BREAK1 - The Function that Supervises all
Breaks 1. 6
What You Can Do In a Break 1. 8
Break Commands 1. 8
Leaving a break with a value
(OK,GO,EVAL,FROM?) 1. 8
Correction of UNBOUND ATOM and
UNDEFINED FUNCTION errors (>, USE) 1. 9
Aborting to Higher Breaks or the Top
Level (↑, ↑↑) 1.10
Examining and Modifying the Context of
a Break 1.11
Searching for a Context on the Stack 1.11
Editing a Form on the Context Stack 1.12
Evaluating a Form in a Higher Context 1.12
Backtrace Commands
Printing the Functions, Forms and Variable
Bindings on the Context Stack 1.15
Breakmacros
User Defined Break Commands 1.17
How to Use the Break Package 1.18
Setting a Break to Investigate a Function 1.18
Tracing the Execution of Functions 1.19
Setting a Break INSIDE a Function 1.19
Removing Breaks and Traces 1.21
Using BREAK0 Directly to Obtain
Special Effects from the
Break Package 1.23
Error Package - Getting Automatic Breaks
When Errors Occur 1.24
Summary of Break Commands 1.25
The LISP Editor 2. 1
Introduction 2. 2
Commands for the New User 2.10
Attention Changing Commands 2.15
Local Attention Changing Commands 2.16
Commands That Search 2.22
Search Algorithm 2.24
Search Commands 2.26
Location Specification 2.30
Commands That Save and Restore the
Edit Chain 2.36
Commands That Modify Structure 2.38
Implementation of Structure
Modification Commands 2.39
The A, B, : Commands 2.41
Form Oriented Editing and
the Role of UP 2.45
Extract and Embed 2.46
The MOVE Command 2.50
Commands That "Move Parentheses" 2.54
TO and THRU 2.57
Commands That Print 2.62
Commands That Evaluate 2.63
Commands That Test 2.66
Macros 2.68
Miscellaneous Commands 2.71
Editdefault 2.78
Editor Functions 2.80
Extended Interpretation of LISP Forms 3. 1
Evaluation of Sequences of Forms
Extended LAMBDA Expressions 3. 1
The Functions PROG1 and PROGN 3. 2
Conditional Evaluation of Forms - SELECTQ 3. 3
Changes to the Handling of Errors 3. 4
Miscellania - APPLY#, NILL 3. 5
Extensions to the Standard Input/Output Functions 4. 1
Project-Programmer Numbers for Disk I/O 4. 1
Saving Function Definitions, etc. on Disk Files 4. 1
Reading Files Back In 4. 1
Printing Circular or Deeply Nested Lists 4. 2
Spacing Control - TAB 4. 2
"Pretty Printing" Function Definitions and
S-Expressions 4. 3
Reading Whole Lines 4. 4
Teletype and Prompt Character Control Functions 4. 5
Read Macros - Extending the LISP READ Routine 4. 6
Functions for Defining Read Macros 4. 6
Using Read Macros 4. 7
Modifying the READ Control Table 4. 8
New Functions on S-Expressions 5. 1
S-Expression Building Functions 5. 1
S-Expression Transforming Functions 5. 3
S-Expression Modifying Functions 5. 4
Mapping Functions with Several Arguments 5. 5
Mapping Functions which use NCONC 5. 6
S-Expression Searching and Substitution Functions 5. 7
Efficiently Working with Atoms as Character Strings 5. 9
New Predicates 6. 1
Data Type Predicates 6. 1
Alphabetic Ordering Predicate 6. 2
Predicates That Return Useful Non-NIL Values 6. 3
Other Predicates 6. 4
New Numeric Functions 7. 1
Minimum and Maximum 7. 1
FORTRAN Functions in LISP 7. 2
Functions for the System Builder 8. 1
Loading Compiled Code into the High Segment 8. 1
The Compiler and LAP 8. 2
Special Variables 8. 2
Removing Excess Entry Points 8. 2
Miscellaneous Useful Functions 8. 3
Initial System Generation 8. 4
The LISP Evaluation Context Stack 9. 1
The Contents of the Context Stack 9. 1
Examining the Context Stack 9. 2
Controlling Evaluation Context 9. 4
Storage Allocation 10. 1
Index INDEX. 1
INTRODUCTION
UCI LISP is a compatible extension of the Stanford LISP
1.6 programming system for the DEC PDP-10. The extensions
make UCI LISP a powerful and convenient interactive
programming environment for research and teaching in
artificial intelligence and advanced list processing
applications. All Stanford LISP programs, (except those
using the BIGNUM package) can be run directly in UCI LISP.
In addition, the extended features of UCI LISP make it much
easier to transfer interpreted LISP programs from BBN LISP
and MIT AI LISP (we have already converted several large
programs, including a version of the Woods' Augmented
Transition Network Parser from BBN LISP, and a version of
Micro-Planner from MIT AI LISP.)
This manual describes the extensions to the Stanford
LISP 1.6 system, and should thus be read in conjunction with
the latest Stanford LISP 1.6 manual, currently SAILON 28.6
(Stanford Artificial Intelligence Laboratory Operating Note
28.6). As can be seen from the relative sizes of the two
documents UCI LISP represents a substantial extension to
Stanford LISP, and from our own experience presents a major
improvement in the habitability of the system for both naive
and experienced users. (A majority of the extensions were
suggested by the features of BBN LISP, probably the best
interactive LISP system in existence, but unfortunately
available only on TENEX, a paged virtual memory system for
the PDP-10, produced by Bolt, Beranek and Newman Inc.)
The major extensions to Stanford LISP can be briefly
described as follows:
1) Improvements in storage utilization:
a) UCI LISP is reentrant and compiled code may be
placed in the sharable high segment
b) the allocator allows reallocation of all
spaces (including Binary Program Space) at any
time
2) Powerful interactive debugging facilities,
including:
a) Sophisticated conditional breakpoint and
function tracing facilities
0 . 1
b) A powerful list structure editor for editing
function definitions and data
c) Facilities for examining, correcting and
continuing to run in the context of a program
which has been interrupted by an error or by a
user initiated temporary interrupt
3) Extensions to the I/O facilities available in the
basic system, including:
a) Convenient I/O to disk files, including use of
project/programmer designations and ways to
save and restore functions and data
b) Read Macros (patterned after MIT AI LISP) for
extending the LISP READ routine
c) A routine for printing circular or deeply
nested expressions
d) Routines to modify the control table of the
LISP READ routine
e) Several useful functions for carriage
positioning, teletype echo and prompt
character control, reading input a line at a
time, etc.
4) Functions for examining and modifying the special
pushdown stack which holds the context of ongoing
computations
5) Error protection facilities:
a) NIL, T and other atoms cannot be easily
damaged by RPLACA, RPLACD, SETQ and SET
b) The system will no longer go into an infinite
loop when searching for the function
definition of the CAR of a form
6) Extended basic functions including:
a) New predicates for data types, and predicates
which return useful values
b) New list construction and modification
functions
c) Multiple sequential form evaluation in LAMBDA
expressions
d) An efficient n-way switch
e) Availability of the FORTRAN mathematical
functions
f) Mapping functions with several arguments, and
ones which build new lists using NCONC to join
segments
0 . 2
As mentioned, we have made UCI LISP a reentrant system
which may be used by several users simultaneously. Thus,
while the new features of UCI LISP require a larger system
than the original Stanford LISP, this impact is minimized in
any environment with more than one LISP user. In addition,
since the basic LISP system contains many features
previously available only in the various extension files
(such as SMILE, ALVINE, TRACE, etc.) or which had to be
written by the user, it is possible to write and debug
meaningful jobs in the basic system, without getting extra
core. The UCI LISP system has a sharable high segment of
14K and a user specific low segment of 8K. Thus, if there
are two users the virtual core load is 30K, while getting
the same capabilities in Stanford LISP would require a load
of 32K for the two users, and of course the improvement is
even more noticeable with more users sharing UCI LISP (about
8K is saved for each additional user).
The ability to put compiled code in the sharable
segment and to reallocate Binary Program Space makes it
possible to build systems in which much of the systems code
is compiled LISP expressions. All of the advantages of
higher level coding are obtained, and the LISP compiler
(borrowed from Stanford with some small modifications)
produces better results than most assembly language coders.
Such partially compiled systems can now be used without
closing off the possibility of the user extending Binary
Program Space to store his own compiled code. In general,
it is now possible to compile a system incrementally. The
user can save the low segment which contains the partially
compiled system, then test out new material in interpreted
form before extending the Binary Program Space in the
segment to load the new compiled material.
The debugging facilities form the bulk of the
extensions to Stanford LISP, and are identical with the
equivalent facilities available in BBN LISP in the summer of
1971. (BBN LISP has been extended in the intervening
period.) They make it possible for the user to track down
bugs in complicated recursive programs by making it easier
for him to investigate the context in which the bug occurred
(e.g. to see at what point erroneous data was passed as an
argument, or at what point the flow of control went awry,
etc.) The user does not have to plan in advance or set
breakpoints to get access to the context of the error. The
system holds the context of any error automatically,
0 . 3
allowing the user to perform whatever investigations he
wishes, and make any corrections which may be useful. This
also makes it possible to patch up a small error, like an
unbound atom or simple undefined function, in the middle of
a large computation and to continue the computation without
having to start from scratch. Similarly, the user can try
out ideas for correcting the error, without leaving the
context of the error, and go on only when he has pinned down
the error and its possible solution. If the information
available at the time the LISP system discovers the error is
insufficient to pin down the cause of the error, the user
can have the system repeat the computation, with a special
trace feature that prints out whatever the user wishes to
know at various points in the computation. (The user can
specify both what data is to be printed and under what
conditions he wishes it printed.) The user can also force
the system to establish a breakpoint anywhere in his
computation, so he can investigate the context before the
error has covered its tracks.
The UCI LISP editor (borrowed with some modifications
from the BBN LISP system) is actually a language for
incremental modification of list structures. It can be used
by a user at a terminal to modify function definitions (even
during the middle of a break while the function is still on
the context stack) or to change complicated data structures.
It can also be used as a subroutine by other functions,
making it convenient for one function to modify another
function. This is actually done by the BREAK package, to
implement the function BREAKIN which inserts a breakpoint at
any arbitrary point in a user function.
The editor can move around in a structure by small
local motions, or by searching for a portion of the
structure which matches some given pattern. It can insert
new items, delete old ones, interchange items, change
structure, embed old items in new structure or extract them
from old structure, etc. In order to be able to edit a
function which is still on the context stack and to have all
of the portions on the context stack be changed at once, the
modifications performed by the editor are physical changes
of the existing structure. Although all the modifications
are "destructive", using RPLACA and RPLACD to make changes
in the given structure, all of the modifications can be
selectively reversed by means of the UNDO feature. Thus the
user can make modifications without worrying about
completely destroying his function definitions by accident.
0 . 4
The editor is a very large, complicated function, and its
documentation indicates that fact. However, the first part
of the editor documentation gives a convenient rundown on
how to use the editor as a novice, and with that the
beginning user can get quite a bit done. By skimming the
remainder of the editor chapter the user can get some idea
of the many extra useful features available, and can slowly
extend his capabilities with the editor. It has been a
common observation that in the process of writing and
debugging a large system, or even a small program, the
average user spends most of his time in editing his
functions. By becoming familiar with all the features of
the list structure editor the user can cut his editing time
considerably, and make large or subtle changes easily. The
user should also bear in mind that the editor is available
as a function which can be used by other functions. This
can make many jobs substantially easier.
NOTE: ALVINE is no longer available in the standard
version of UCI LISP because we believe that the new editor
and I/O facilities are substantially better than those
provided by ALVINE. (There is an assembly switch which
makes it possible to run ALVINE in UCI LISP if necessary.)
Some of the extended I/O facilities of UCI LISP were
available in SMILE, etc., but putting them in the shared
system saves core. The Read Macro facility is a great
convenience and makes using Micro-Planner much simpler. The
user-modified READ control table is more general than that
available in the Stanford SCAN package (which is still
useful and available), and the new SPRINT is faster than the
original. The other functions are quite convenient, and
will make many tasks simpler.
The special pushdown list has been extended to provide
the equivalent of the BBN LISP context stack. This is the
backbone of the ERROR and BREAK packages, since it enables
running programs to examine their context, and to change it
if necessary. The stack functions, particularly RETFROM and
OUTVAL make it possible to experiment with various control
regimes, where subordinate functions can abort and return
from higher level functions on the basis of local
information. Indiscriminate fooling around with the stack
is likely to produce peculiar and unwanted results, but the
stack functions can be extremely helpful at times.
0 . 5
The error protection facilities are an attempt to catch
some of the common errors of novices (and experienced users
too) which can clobber the system. There are few things
more confusing than what happens to the system when the
value of NIL is no longer NIL, or if the value of T becomes
NIL. In Stanford LISP this could easily happen if SETQ or
SET received a list as a first argument. This can no longer
happen in UCI LISP. Similarly, Stanford LISP occasionally
went into infinite loops because a form had a CAR which was
NIL or had no function definition and evaluated to NIL.
This has been corrected.
The extended basic functions are ones which were of
great use in writing the editor, BREAK package, etc., and in
bringing up translated versions of BBN LISP and MIT AI LISP
programs. The multiple form LAMBDA expression and the n-way
switch SELECTQ should make many programming jobs much more
convenient, as should the availability of mapping functions
with several arguments. The user will almost certainly
profit from skimming through the chapters on these extended
features, just to know what is available.
0 . 6
Credits and Acknowledgements
The design and overall direction of the implementation
of this system are the responsibility of Robert Bobrow, who
also made the first modifications to Stanford LISP,
including the original error package, accessible context
stack and storage reallocator. In large part the existence
of the final system and its extensive documentation is due
to the Herculean efforts of Daryle Lewis, who did the bulk
of the modifications to the assembly language code
(including making Stanford LISP reentrant) and corrected the
compiler and LAP systems. He singlehandedly transferred the
entire BBN LISP editor and its documentation to our system,
and in general performed vital and arduous design,
programming and documentation tasks too numerous to mention.
Richard Burton did yeoman's labor by transferring (and
extending) the BBN LISP ERROR and BREAK packages, and
providing their documentation. Whitfield Diffie of Stanford
has helped us out of several sticky problems with the LISP
system and its compiler. The original implementation of the
editor and several I/O functions is due to Rodger Knaus, as
well as many helpful suggestions. Finally, but of vital
importance, is Alan Bell, whose great knowledge of the
PDP-10 operating system helped us through many rough times,
and who has done much of the transferring of BBN LISP and
MIT AI LISP programs.
We are triply indebted to the designers, implementers
and documenters of BBN LISP, particularly Daniel Bobrow and
Warren Teitelman. Most of the debugging and interactive
facilities as well as the general design philosophy of UCI
LISP were inspired by the BBN LISP system. Secondly, we
were able to use much of their code directly, since it was
written in LISP, making it possible to obtain a large,
well-written and debugged system in a fraction of the time
and effort it would have taken to write it from scratch.
Finally, we have made extensive use of the BBN LISP TENEX
REFERENCE MANUAL as a source of raw material for our
documentation. In particular, much of the material in the
chapters on the BREAK and ERROR packages and the editor is a
revised version of the material in the BBN LISP MANUAL. We
take full responsibility for the errors and deficiencies
produced by such an arrangement, while greatfully
acknowledging BBN's aid in providing much of the basic
documentation. We are also in debt to several people at BBN
0 . 7
for their aid in obtaining and explaining this material,
particularly Jim Goodwin, Alice Hartley and the director of
the Artificial Intelligence Group, Jaime Carbonell.
This manual is the work of many people as well as the
listed authors - in particular Warren Teitelman, formerly of
BBN and now at Xerox Palo Alto Research Center, who produced
the original BBN LISP documentation and the lions share of
the original code. We are also in debt to Marion Kaufman
and Phyllis Siegel who did daily battle with the PDP-10 to
produce the RUNOFF files from which this documentation is
produced.
Last, but most assuredly not least in the roster of
those who have made this system possible are Lynette Bobrow,
Kathy Burton and Connie Lewis who lived through the many
discussions, all night programming sessions and
battle-fatigue of the year during which this system was
implemented.
ENJOY, ENJOY!
0 . 8
1.1 DEBUGGING FACILITIES
Introduction
Debugging a collection of LISP functions involves
isolating problems within particular functions and/or
determining when and where incorrect data are being
generated and transmitted. In the UCI LISP system, there
are five facilities which aid the user in monitoring his
program. One of these is the Error Package which takes
control whenever an error occurs in a program and which
allows the user to examine the state of the world (see
section on 'ERROR PACKAGE'). Another facility allows the
user to temporarily interrupt his computation and examine
its progress. The other three facilities (BREAK, TRACE and
BREAKIN) allow the user to (temporarily) modify selected
function definitions so that he can follow the flow of
control in his programs. All of these facilities use the
same system function, BREAK1, as the user interface.
BREAK, BREAKIN and TRACE together are called the Break
Package. BREAK and TRACE can be used on compiled and system
functions as well as EXPR's, FEXPR's and MACRO's. BREAKIN
can be used only with interpreted functions.
BREAK modifies the definition of a function FN, so that
if a break condition (defined by the user) is satisified,
the process is halted temporarily on a call to FN. The user
can then interrogate the state of the machine, perform any
computations, and continue or return from the call.
TRACE modifies a definition of a function FN so that
whenever FN is called, its arguments (or some other values
specified by the user) are printed. When the value of FN is
computed it is printed also.
BREAKIN allows the user to insert a breakpoint inside
an expression defining a function. When the breakpoint is
reached and if a break condition (defined by the user) is
satisfied, a temporary halt occurs and the user can again
investigate the state of the computation.
The two examples on pages 1.3 and 1.4 illustrate these
facilities. In the first example, the user traces the
function FACTORIAL. TRACE redefines FACTORIAL so that it
calls BREAK1 in such a way that it prints some information,
in this case the arguments and value of FACTORIAL, and then
1 . 1
goes on with the computation. When an error occurs on the
fifth recursion, BREAK1 reverts to interactive mode, and a
full break occurs. The situation is then the same as though
the user had originally performed (BREAK FACTORIAL) instead
of (TRACE FACTORIAL), and the user can evaluate various LISP
forms and direct the course of the computation. In this
case, the user examines the variable N, instructs BREAK1 to
change L to 1 and continue. The > command, following an
UNBOUND ATOM or UNDEFINED FUNCTION error, tells BREAK1 to
use the next expression instead of the atom which caused the
error. The > command does a destructive replacement of, in
this case, 1 for L, and saves an edit step by correcting the
typo in the function definition. The rest of the tracing
proceeds without incident. The function UNTRACE restores
FACTORIAL to its original definition.
In the second example, the user has written Ackermann's
function. He then uses BREAK to place a call to BREAK1
around the body of the function. He indicates that ACK is
to be broken when M equals N and that before the break
occurs, the arguments to ACK are to be printed. While
calculating (ACK 2 1), ACK is called twice when M = N.
During the first of these breaks, the user prints out a
backtrace of the function names and variable bindings. He
continues the computation with a GO which causes the value
of (ACK 1 1), 3, to be printed before the break is released.
The second break is released with an OK which does not print
the result of (ACK 1 1). The function UNBREAK with an
argument T restores the latest broken or traced function to
its original definition.
For further information on how to use BREAK, TRACE and
BREAKIN, see the section on The Break Package.
1 . 2
*(DE FACTORIAL (N)
(COND ((ZEROP N) L)
(T (TIMES N (FACTORIAL (SUB1 N))))))
FACTORIAL
*(TRACE FACTORIAL)
(FACTORIAL)
*(FACTORIAL 4)
ENTER FACTORIAL:
! N = 4
! ENTER FACTORIAL:
! ! N = 3
! ! ENTER FACTORIAL:
! ! ! N = 2
! ! ! ENTER FACTORIAL:
! ! ! ! N = 1
! ! ! ! ENTER FACTORIAL:
! ! ! ! ! N = 0
L
UNBOUND VARIABLE - EVAL
(L BROKEN)
1:N
0
1:> 1
! ! ! ! FACTORIAL = 1
! ! ! FACTORIAL = 1
! ! FACTORIAL = 2
! FACTORIAL = 6
FACTORIAL = 30
30
(UNTRACE FACTORIAL)
(FACTORIAL)
*(FACTORIAL 4)
30
1 . 3
*(DE ACK (M N)
(COND ((ZEROP M) (ADD1 N))
((ZEROP N) (ACK (SUB1 M) 1))
(T (ACK (SUB1 M) (ACK M (SUB1 N))))))
ACK
*(BREAK (ACK (EQ N M) (ARGS)))
(ACK)
*(ACK 2 1)
M = 1
N = 1
(ACK BROKEN)
1:BKFV
M = 1
N = 1
ACK
M = 2
N = 0
ACK
M = 2
N = 1
ACK
1:GO
3
M = 1
N = 1
(ACK BROKEN)
1:OK
5
*(UNBREAK T)
(ACK)
1 . 4
Interrupting a computation-REE and DDT
A useful feature for debugging is a way to temporarily
suspend computation. If the user wishes to know how his
computation is proceeding (i.e. is he in an infinite loop
or is system response poor). Then type Control-C twice
(which will cause a return to the monitor) followed by
either REE or DDT. After typing REE the user must respond
with one of the following control characters; Control-H,
Control-B, Control-G, Control-E or Control-Z. Typing DDT is
equivalent to typing REE followed by Control-H.
1. Control-H: This will cause the computation to continue,
but a break will occur the next time a function is called
(except for a compiled function called by a compiled
function). A message of the form (-- BROKEN) is typed and
the user is in BREAK1 (see the next section). He can
examine the state of the world and continue or stop his
computation using any of the BREAK1 commands. WARNING It is
possible to get into an infinite loop that does not include
calls to functions other than compiled functions called by
compiled functions. These will continue to run. (In such
cases, type Control-C twice, followed by REE, followed by
one of the other control characters).
2. Control-B: This will cause the system to back up to the
last expression to be evaluated and cause a break (putting
the user in BREAK1 with all the power of BREAK1 at the
user's command. This does not include calls to compiled
functions by other compiled functions.
3. Control-G: This causes an (ERR ERRORX) which returns to
the last (ERRSET ERRORX). This enables the user to
Control-C out of the Break package or the Editor, reenter
and return to the appropriate command level. (i.e. if the
user were several levels deep in the Editor for example,
Control-G will return him to the correct command level of
the Editor).
1 . 5
4. Control-E: This does an (ERR NIL), which return NIL to
the last ERRSET. (See section on changes to ERR and
ERRSET).
5. Control-Z: This returns the user to the top-level of
LISP, (i.e. either the READ-EVAL-PRINT loop or the current
INITFN).
1 . 5 . 1
BREAK1
The heart of the debugging package is a function called
BREAK1. BREAK and TRACE redefine your functions in terms of
BREAK1. When an error occurs control is passed to BREAK1.
The DDT break feature is also implemented using BREAK1.
Whenever LISP types a message of the form (-- BROKEN)
followed by 'n:' the user is then 'talking to' BREAK1, and
he is 'in a break.' BREAK1 allows the user to interrogate
the state of the world and affect the course of the
computation. It uses the prompt character ':' to indicate
it is ready to accept input(s) for evaluation, in the same
way as the top level of LISP uses '*'. The n before the ':'
is the level number which indicates how many levels of
BREAK1 are currently open. The user may type in an
expression for evaluation and the value will be printed out,
followed by another ':'. Or the user can type in one of the
commands described below which are specifically recognized
by BREAK1 (for summary of commands see Table I, page 1.25).
Since BREAK1 puts all of the power of LISP at the
user's command, he can do anything he can do at the top
level of LISP. For example, he can define new functions or
edit existing ones, set breaks, or trace functions. The
user may evaluate an expression, see that the value was
incorrect, call the editor, change a function, and evaluate
the expression again, all without leaving the break.
It is important to emphasize that once a break occurs,
the user is in complete control of the flow of the
computation, and the computation will not proceed without
specific instruction from him. Only if the user gives one
of the commands that exits from the break (GO, OK, RETURN,
FROM?=, EX) will the computation continue. If the user
wants to abort the computation, this also can be done (using
↑ or ↑↑).
Note that BREAK1 is just another LISP function, not a
special system feature like the interpreter or the garbage
collector. It has arguments and returns a value, the same
as any other function. A call to BREAK1 has the form
(BREAK1 BRKEXP BRKWHEN BRKFN BRKCOMS BRKTYPE)
The arguments to BREAK1 are: BRKWHEN is a LISP function
which is evaluated to determine if a break will occur. If
1 . 6
BRKWHEN returns NIL, BRKEXP is evaluated and returned as the
value of the BREAK1. Otherwise a break occurs. BRKFN is
the name of the function being broken and is used to print
an identifying message. BRKCOMS is a list of command lines
(as returned by READLINE) which are executed as if they had
been typed in from the teletype. The command lines on
BRKCOMS are executed before commands are accepted from the
teletype, so that if one of the commands on BRKCOMS causes a
return, a break occurs without the need for teletype
interaction. BRKTYPE identifies the type of the break. It
is used primarily by the error package and in all cases the
user can use NIL for this argument.
The value returned by BREAK1 is called 'the value of
the break.' The user can specify this value explicitly by
using the RETURN command described below. In most cases,
however, the value of the break is given implicitly, via a
GO or OK command, and is the result of evaluating 'the break
expression,' BRKEXP.
BRKEXP is, in general, an expression
equivalent to the computation that would have
taken place had no break occurred. In other
words, one can think of BREAK1 as a fancy EVAL,
which permits interaction before and after
evaluation. The break expression then corresponds
to the argument to EVAL. For BREAK and TRACE,
BRKEXP is a form equivalent to that of the
function being traced or broken. For errors,
BRKEXP is the form which caused the error. For
DDT breaks, BRKEXP is the next form to be
evaluated.
1 . 7
WHAT YOU CAN DO IN A BREAK
Break Commands
Once in a break, in addition to evaluating expressions,
the user can ask BREAK1 to perform certain useful actions by
giving it atomic items as "break commands". The following
commands can be typed in by the user or may be put on the
list BRKCOMS. TABLE I (page 1.25) is a summary of these
commands.
All printing in BREAK1 is done by calling (%PRINFN
expr). %PRINFN is an atom (not a function) which should
evaluate to the name of a printing function of one argument.
%PRINFN is initialized to use PRINTLEV because it can print
circular lists, which quite often result from errors.
PRINTLEV only prints lists to a depth of 6. This depth
parameter may be changed by setting the value of %LOOKDPTH.
PRINTLEV is necessarily slow and if you are not printing
circular structures, traces can be speeded up greatly by
changing the value of %PRINFN to PRIN1.
GO
Releases the break and allows the computation
to proceed. BREAK1 evaluates BRKEXP, its first
argument, prints the value, and returns it as the
value of the break. BRKEXP is the expression set up
by the function that called BREAK1. For BREAK or
TRACE, BRKEXP is equivalent to the body of the
definition of the broken function. For the error
package, BRKEXP is the expression in which the error
occurred. For DDT breaks, it is the next form to be
evaluated.
OK
Same as GO except that the value of BRKEXP is
not printed.
EVAL
Causes BRKEXP to be evaluated. The break is
maintained and the value of the evaluation is
printed and bound on the variable !VALUE. Typing GO
or OK will not cause reevaluation of BRKEXP
following EVAL but another EVAL will. EVAL is a
useful command when the user is not sure whether or
not the break will produce the correct value and
1 . 8
wishes to be able to do something about it if it is
wrong.
RETURN form
The form is evaluated and its value is returned
as the value of the break. For example, one might
use the EVAL command and follow this with
RETURN (REVERSE !VALUE).
FROM?= form
This permits the user to release the break and
return to a previous context with form to be
evaluated. For details see context commands.
> [or ->] expr
For use either with UNBOUND ATOM error or
UNDEFINED FUNCTION error. Replaces the expression
containing the error with expr (not the value of
expr) e.g.,
FOO1
UNDEFINED FUNCTION
(FOO1 BROKEN)
1:> FOO
changes FOO1 to FOO and continues the computation.
Expr need not be atomic, e.g.,
FOO
UNBOUND ATOM
(FOO BROKEN)
1:> (QUOTE FOO)
For UNDEFINED FUNCTION breaks, the user can specify
a function and its first argument, e.g.,
MEMBERX
UNDEFINED FUNCTION
(MEMBERX BROKEN)
1:> MEMBER X
Note that in the some cases the form containing the
offending atom will not be on the stack (notably,
after calls to APPLY) and in these cases the
function definition will not be changed. In most
cases, however, > will correct the function
definition.
1 . 9
1.10 USE x FOR y
Causes all occurrences of y in the form on the
stack at LASTPOS (for Error breaks, unless a F
command has been used, this form is the one in which
the error occurred.) to be replaced (RPLACA'ed) by
x. Note: This is a destructive change to the
s-expression involved and will, for example,
permanently change the definition of a function and
make a edit step unnecessary.
↑
Calls ERR and aborts the break. This is a
useful way to unwind to a higher level break. All
other errors, including those encountered while
executing the GO, OK, EVAL, and RETURN commands,
maintain the break.
↑↑
This returns control directly to the top level
of LISP.
ARGS
Prints the names and the current values of the
arguments of BRKFN. In most cases, these are the
arguments of the broken function.
1 . 10
Context Commands
All information pertaining to the evaluation of forms
in LISP is kept on the special push down stack. Whenever a
form is evaluated, that form is placed on the special push
down stack. Whenever a variable is bound, the old binding
is saved on the special push down stack. The context (the
bindings of free variables) of a function is determined by
its position in the stack. When a break occurs, it is often
useful to explore the contexts of other functions on the
stack. BREAK1 allows this by means of a context pointer,
LASTPOS, which is a pointer into the special push down
stack. BREAK1 contains commands to move the context pointer
and to evaluate atoms or expressions as of its position in
the stack. For the purposes of this document, when moving
through the stack, "backward" is considered to be toward the
top level or, equivalently, towards the older function calls
on the stack.
F [or &] arg1 arg2 ... argN
Resets the variable LASTPOS, which establishes
a context for the commands ?=, USE, EX and FROM?=,
and the backtrace commands described below. LASTPOS
is the position of a function call on the special
push down list. It is initialized to the function
just before the call to BREAK1.
F takes the rest of the teletype line as its
list of arguments. F first resets LASTPOS to the
function call just before the call to BREAK1, and
then for each atomic argument, F searches backward
for a call to that atom. The following atoms are
treated specially:
F
When used as the first argument
caused LASTPOS not to be reset to
above BREAK1 but continues searching
from the previous position of LASTPOS.
Numbers
If negative, move LASTPOS back
(i.e. towards the top level) that
number of calls, if positive, forward.
1 . 11
←
Search forward instead of
backward for the next atom
Example:
If the special push-down stack looks like
BREAK1 (13)
FOO (12)
SETQ (11)
COND (10)
PROG (9)
FIE (8)
COND (7)
FIE (6)
COND (5)
FIE (4)
COND (3)
PROG (2)
FUM (1)
then
F FIE COND will set LASTPOS to to (7)
F & COND will then set LASTPOS to (5)
F FUM ← FIE will stop at (4)
F & 2 will then move LASTPOS to (6)
F will reset LASTPOS to (12)
If F cannot successfully complete a search,
for argN or if argN is a number and F cannot move
the number of functions asked, "argN?" is typed.
In either case, LASTPOS is restored to its value
before the F command was entered. Note: It is
possible to move past BRKEXP (i.e. into the break
package functions) when searching or moving
forwards.
When F finishes, it types the name of the
function at LASTPOS.
F can be used on BRKCOMS. In which case, the
remainder of the list is treated as the list of
arguments. (i.e. (F FOO FIE FOO)
1 . 12
EDIT arg1 arg2 ... argN
EDIT uses its arguments to reset LASTPOS in
the same manner as the F command. The form at
LASTPOS is then given to the LISP Editor. This
commands can often times save the user from the
trouble of calling EDITF and the finding the
expression that he needs to edit.
?= arg1 arg2 ... argN
This is a multi-purpose command. Its most
common use is to interrogate the value(s) of the
arguments of the broken function, (ARGS is also
useful for this purpose.) e.g. if FOO has three
arguments (X Y Z), then typing ?= to a break of
FOO, will produce:
n:?=
X = value of X
Y = value of Y
Z = value of Z
?= takes the rest of the teletype line as its
arguments. If the argument list to ?= is NIL, as
in the above case, it prints all of the arguments
of the function at LASTPOS. If the user types
?= X (CAR Y)
he will see the value of X, and the value of (CAR
Y). The difference between using ?= and typing X
and (CAR Y) directly into BREAK1 is that ?=
evaluates its inputs as of LASTPOS. This provides
a way of examining variables or forms as of a
particular point on the stack. For example,
F (FOO FOO)
?= X
will allow the user to examine the value of X in an
earlier call to FOO.
?= also recognizes numbers as referring to the
correspondingly numbered argument. Thus
:F FIE
:?= 2
1 . 13
will print the name and value of the second
argument of FIE (providing FIE is not compiled).
?= can also be used on BRKCOMS, in which case
the remainder of the list on BRKCOMS is treated as
the list of arguments. For example, if BRKCOMS is
((EVAL) (?= X (CAR Y)) GO)), BRKEXP will be
evaluated, the values of X and (CAR Y) printed, and
then the function exited with its value being
printed.
FROM?= [form]
FROM?= exits from the break by undoing the
special push down stack back to LASTPOS. If FORM
is NIL or missing, re-evaluation continues with the
form on the push down stack at LASTPOS. If FORM is
not NIL, the function call on the push down stack
at LASTPOS is replaced by FORM and evaluation
continues with FORM. FORM is evaluated in the
context of LASTPOS. There is no way of recovering
the break because the push down stack has been
undone. FROM?= allows the user to, among other
things, return a particular value as the value of
any function call on the stack. To return 1 as the
value of the previous call to FOO:
:F FOO
:FROM?= 1
Since form is evaluated after it is placed on the
stack, a value of NIL can be returned by using
(QUOTE NIL).
EX
EX exits from the break and re-evaluates the
form at LASTPOS. EX is equivalent to FROM?= NIL.
1 . 14
Backtrace Commands
The backtrace commands print information about
function calls on the special push down list. The
information is printed in the reverse order that the calls
were made. All backtraces start at LASTPOS.
BKF
BKF gives a backtrace of the names of
functions that are still pending.
BKE
BKE gives a backtrace of the expressions which
called functions still pending (i.e. It prints the
function calls themselves instead of only the names
as in BKF).
BK
BK gives a full backtrace of all expressions
still pending.
All of the backtrace commands may be suffixed by a 'V'
and/or followed by an integer. If the integer is included,
it specifies how many blocks are to be printed. The
limiting point of a block is a function call. This form is
useful when working on a Data Point. Using the integer
feature in conjunction with the F command, which moves
LASTPOS, the user can display any contiguous part of the
backtrace. If a 'V' is included, variable bindings are
printed along with the expressions in the backtrace.
Example:
BKFV would print the names and variable
bindings of the functions called before
LASTPOS.
BKV 5 would print everything (expressions and
variables) for 5 blocks before LASTPOS.
1 . 15
The output of the backtrace commands deserves some
explanation. Right circular lists are only printed up to
the point where they start repeating and are closed with
'...]' instead of a right parenthesis. Lists are only
printed to a depth of 2. /#/ Is a notation which
represents "the previous expression". For example, (SETQ
FIE (FOO)) would appear in a BK backtrace as
(FOO)
(SETQ FIE /#/)
1 . 16
Breakmacros
Whenever an atomic command is encountered by BREAK1
that it does not recognize, either via BRKCOMS or the
teletype, it searches (using ASSOC) the list BREAKMACROS to
see if the atom has been defined as a break macro. The
form of BREAKMACROS definitions is ( ... (atom ttyline1
ttyline2 ... ttylineN) ... ). ATOM is the command name.
ARGS is the argument(s) for the macro. The arguments of a
breakmacro are assigned values from the remainder of the
command line in which the macro is called. If ARGS is
atomic, it is assigned the remainder of the command line as
its value. If ARGS is a list, the elements of the rest of
the command line are assigned to the variables, in order.
If there are more variables in ARGS then items in the rest
of the command line, a value of NIL is filled in. Extra
items on the command line are ignored. The TTYLINEs are
the body of the breakmacro definition and are lists of
break commands or forms to be evaluated. If the atom is
defined as a macro, (i.e. is found on BREAKMACROS) BREAK1
assigns values to the variables in ARGS, substitutes these
values for all occurrences of the variables in TTYLINEs and
appends the TTYLINEs to the front of BRKCOMS. When BREAK1
is ready to accept another command, if BRKCOMS is non-NIL
it takes the first element of BRKCOMS and processes it
exactly as if it had been a line input from the teletype.
This means that a macro name can be defined to expand to
any arbitrary collection of expressions that the user could
type in. If the command is not contained in BREAKMACROS,
it is treated as a function or variable as before.
Example: a command PARGS to print the arguments of the
function at LASTPOS could be defined by evaluating:
(NCONC BREAKMACROS (QUOTE ((PARGS NIL (?=)))))
A command FP which finds a place on the SPD stack and
prints the form there can be defined by:
(NCONC BREAKMACROS (QUOTE (FP X (F . X) ((PRINT (SPDLRT
LASTPOS))))))
1 . 17
BREAK PACKAGE
How To Set A Break
The following functions are useful for setting and
unsetting breaks and traces.
Both BREAK and TRACE use a function BREAK0 to do the
actual modification of function definitions. When BREAK0
breaks a SUBR or an FSUBR, it prints a message of the form
(--- . ARGUMENT LIST?). The user should respond with a
list of arguments for the function being broken. (FSUBR's
take only one argument and BREAK0 checks for this.) The
arguments on this list are actually bound during the calls
to the broken function and care should be taken to insure
that they do not conflict with free variables. For
LSUBR's, the atom N? Is used as the argument. It is
possible to GRINDEF and edit functions that are traced or
broken. BROKENFNS is a list of the functions currently
broken. TRACEDFNS is a list of the functions currently
traced.
BREAK
BREAK is an FEXPR. For each atomic argument, it
breaks the function named each time it is called. For each
list in the form (fn1 IN fn2), it breaks only those
occurrences of FN1 which appear in FN2. This feature is
very useful for breaking a function that is called from
many places, but where one is only interested in the call
from a specific function, e.g. (RPLACA IN FOO), (PRINT IN
FIE), etc. For each list not in this form, it assumes that
the CAR is a function to be broken; the CADR is the break
condition; (When the fuction is called, the break condition
is evaluated. If it returns a non-NIL value, the break
occurs. Otherwise, the computation continues without a
break.) and the CDDR is a list of command lines to be
performed before an interactive break is made (see BRWHEN
and BRKCOMS of BREAK1). For example,
(BREAK FOO1 (FOO2 (GREATERP N 5) (ARGS)))
will break all calls to FOO1 and all calls on FOO2 when N
is greater than 2 after first printing the arguments of
FOO2.
1 . 18
(BREAK ((FOO4 IN FOO5) (MINUSP X)))
will break all calls to FOO4 made from FOO5 when X is
negative.
Examples:
(BREAK FOO)
(BREAK ((GET IN FOO) T (GO)))
(BREAK (SETQ (EQ N 1) ((PRINT (QUOTE N=1)))(?= M)))
TRACE
TRACE is an FEXPR. For each atomic argument, it
traces the function named (see form on page 1.3) each time
it is called. For each list in the form (fn1 IN fn2), it
traces only those calls to FN1 that occur within FN2. For
each list argument not in this form, the CAR is the
function to be traced, and the CDR is a list of variables
(or forms) the user wishes to see in the trace.
For example, (TRACE (FOO1 Y) (SETQ IN FOO3)) will
cause both FOO1 and SETQ IN FOO3 to be traced. SETQ's
argument will be printed and the value of Y will be printed
for FOO1.
TRACE uses the global variable #%INDENT to keep its
position on the line. The printing of output by TRACE is
printed using %PRINFN (see page 1.9). TRACE can therefore
be pretty printed by:
(SETQ %PRINFN (QUOTE PRETPRIN))
(DE PRETPRIN (FORM)
(SPRINT FORM (*PLUS 10 #%INDENT)))
Examples:
(TRACE FOO)
(TRACE *TIMES (SELECTQ IN DOIT))
(TRACE (EVAL IN FOO))
(TRACE (TRY M N X (*PLUS N M)))
Note: The user can always call BREAK0 himself to
obtain combinations of options of BREAK1 not directly
available with BREAK and TRACE (see section on BREAK0
below). These functions merely provide convenient ways of
calling BREAK0, and will serve for most uses.
1 . 19
1.20 BREAKIN
BREAKIN enables the user to insert a break, i.e., a
call to BREAK1, at a specified location in an interpreted
function. For example, if FOO calls FIE, inserting a break
in FOO before the call to FIE is similar to breaking FIE.
However, BREAKIN can be used to insert breaks before or
after prog labels, particular SETQ expressions, or even the
evaluation of a variable. This is because BREAKIN operates
by calling the editor and actually inserting a call to
BREAK1 at a specified point inside of the function.
The user specifies where the break is to be inserted
by a sequence of editor commands. These commands are
preceded by BEFORE, AFTER, or AROUND, which BREAKIN uses to
determine what to do once the editor has found the
specified point, i.e., put the call to BREAK1 BEFORE that
point, AFTER that point, or AROUND that point. For
example, (BEFORE COND) will insert a break before the first
occurrence of COND, (AFTER COND 2 1) will insert a break
after the predicate in the first COND clause, (AFTER BF
(SETQ X F)) after the last place X is set. Note that
(BEFORE TTY:), (AROUND TTY:) or (AFTER TTY:) permit the
user to type in commands to the editor, locate the correct
point, and verify it for himself using the P command, if he
desires. Upon exit from the editor with OK, the break is
inserted. (A STOP command typed to TTY: produces the same
effect as an unsuccessful edit command in the original
specification, e.g., (BEFORE CONDD). In both cases, the
editor aborts, and BREAKIN types (NOT FOUND).)
for BREAKIN BEFORE or AFTER, the break expression is
NIL, since the value of the break is usually not of
interest. For BREAKIN AROUND, the break expression will be
the indicated form. When in the break, the user can use
the EVAL command to evaluate that form, and see its value,
before allowing the computation to proceed. For example,
if the user inserted a break after a COND predicate, e.g.,
(AFTER (EQUAL X Y)), he would be powerless to alter the
flow fo computation if the predicate were not true, since
the break would not be reached. However, by breaking
(AROUND (EQUAL X Y)), he can evaluate the break expression,
i.e., (EQUAL X Y), see its value and evaluate something
else if he wished.
The message typed for a BREAKIN break identifies the
location of the break as well as the function, e.g.,
1 . 20
((FOO (AFTER COND 2 1)) BROKEN).
BREAKIN is an FEXPR which has a maximum of four
arguments. The first argument is the function to be broken
in. The second argument is a list of editor commands,
preceded by BEFORE, AFTER, or AROUND, which specifies the
location inside the function at which to break. If there
is no second argument, a value of (BEFORE TTY:) is assumed.
(See earlier discussion.) The third and fourth arguments
are the break condition and the list of commands to be
performed before the interactive break occurs, (BRKWHEN and
BRKCOMS for BREAK1) respectively. If there is no third
argument, a value of T is assumed for BRKWHEN which causes
a break each time the BREAKIN break is executed. If the
fourth argument is missing, a value of NIL is assumed. For
example,
(BREAKIN FOO (AROUND COND))
inserts a break around the first call to COND in FOO.
It is possible to insert multiple break points, with a
single call to BREAKIN by using a list of the form ((BEFORE
...) ... (AROUND ...)) as the second argument. It is also
possible to BREAK or TRACE a function which has been
modified by BREAKIN, and conversely to BREAKIN a function
which is broken or traced. UNBREAK restores functions
which have been broken in. GRINDEF makes no attempt to
correct the modification of BREAKIN so functions should be
unbroken before they are stored on disk.
Examples:
(BREAKIN FOO (AROUND TTY:) T (?= M N) ((*PLUS X Y)))
(BREAKIN FOO2 (BEFORE SETQ) (EQ X Y))
UNBREAK
UNBREAK is an FEXPR. It takes a list of functions
modified by BREAK or BREAKIN and restores them to their
original state. It's value is the list of functions that
were "unbroken".
(UNBREAK T) will unbreak the function most recently
broken.
(UNBREAK) will unbreak all of the functions currently
1 . 21
broken (i.e. all those on BROKENFNS).
If one of the functions is not broken, UNBREAK has a
value of (fn NOT BROKEN) for that function and no changes
are made to fn.
Note: If a function is both traced and broken in,
either UNTRACE or UNBREAK will restore the original
function definition.
UNTRACE
UNTRACE is an FEXPR. It takes a list of functions
modified by TRACE and restores them to their original
state. It's value is the list of functions that were
"untraced".
(UNTRACE T) will unbreak the function most recently
traced.
(UNTRACE) will untrace all of the functions currently
traced (i.e. all those on TRACEDFNS).
If one of the functions is not traced, UNTRACE has a
value of (fn NOT BROKEN) for that function and no changes
are made to fn.
1 . 22
BREAK0 [FN WHEN COMS]
BREAK0 is an EXPR. It sets up a break on the function
FN by redefining FN as a call to BREAK1 with BRKEXP a form
equivalent to the definition of FN, and WHEN, FN and COMS
as BRKWHEN, BRKFN, and BRKCOMS, respectively (see BREAK1).
BREAK0 also adds FN to the front of the list BROKENFNS.
It's value is FN.
If FN is non-atomic and of the form (fn1 IN fn2),
BREAK0 first calls a function which changes the name of fn1
wherever it appears inside of fn2 to that of a new
function, fn1-IN-fn2, which is initially defined as fn1.
Then BREAK0 proceeds to break on fn1-IN-fn2 exactly as
described above. This procedure is useful for breaking on
a function that is called from many places, but where one
is only interested in the call from a specific function,
e.g. (RPLACA IN FOO), (PRINT IN FIE), etc. This only works
in interpreted functions. If fn1 is not found in fn2,
BREAK0 returns the value (fn1 NOT FOUND IN fn2).
If FN is non-atomic and not of the above form, BREAK0
is called for each member of FN using the same values for
WHEN and COMS specified in this call to BREAK0. This
distributivity permits the user to specify complicated
break conditions without excessive retyping, e.g.,
(BREAK0 (QUOTE (FOO1 ((PRINT PRIN1)IN (FOO2 FOO3))))
(QUOTE (EQ X T))
(QUOTE ((EVAL) (?= Y Z) OK)))
will break on FOO1, PRINT-IN-FOO2, PRINT-IN-FOO3,
PRIN1-IN-FOO2, and PRIN1-IN-FOO3.
If FN is non-atomic, the value of BREAK0 is a list of
the individual values.
For example, BREAK0 can be used to trace the changing
of particular values by SETQ in the following manner:
*(SETQ VARLIST (QUOTE (X Y FOO)))
*(BREAK0 (QUOTE SETQ) (QUOTE (MEMQ (CAR XXXX) VARLIST))
* (QUOTE ((TRACE) (?=)(UNTRACE))))
(SETQ ARGMENTS?)*(XXXX)
SETQ will be traced whenever CAR of its argument (SETQ is
an FSUBR) is a member of VARLIST.
1 . 23
ERROR PACKAGE
Introduction
When an error occurs during the evaluation of a LISP
expression, control is turned over to the Error Package.
The I/O is forced to the TTY (channel NIL) but will be
restored to its previous channels if the user continues the
evaluation. The idea behind the error package is that it
may be possible to 'patch up' the form in which the error
occurred and continue. Or, at least, that you can find the
cause of the error more easily if you can examine the state
of the world at the time of the error. Basically, what the
Error Package does is call BREAK1 with BRKEXP set to the
form in which the error occurred. This puts the user 'in a
break' around the form in which the error occurred. BREAK1
acts just like the top level of the interpreter with some
added commands (see section on BREAK1). The main
difference when you are in the Error Package is that the
variable bindings that were in effect when the error
occurred are still in effect. Furthermore, the expressions
that were in the process of evaluation are still pending.
While in the Error Package, variables may be examined or
changed, and functions may be defined or edited just as if
you were at the top level. In addition, there are several
ways in which you can abort or continue from the point of
error. In particular, if you can patch up the error, you
can continue by typing OK. If you can't patch the error, ↑
will get you out of the break. When you are in the error
package, the prompt character is ':' and is preceded by a
level number. Note: if you don't want the error package
invoked for some reason, it can be turned off by evaluating
(*RSET NIL). Similarly, (*RSET T) will turn the error
package back on.
Commands
There are several atoms which will cause special
actions when typed into BREAK1 (the error package). These
actions are useful for examining the push down stack (e.g.
backtraces), changing forms and exiting from the break in
various ways. Table I (on the next page) gives a summary
of the actions. For a complete description, see the
section on 'What You Can Do In A Break'.
1 . 24
Table I
Break Package Command Summary
(for complete description see pp. 1.8-1.16)
Command Action
GO Evaluates BRKEXP, prints its value,
and continues with this value
OK Same as GO but no print of value
EVAL Reevaluate BRKEXP and print its value.
Its value is bound to !VALUE
RETURN xx Evaluate xx and continue with its value
↑ Escape one level of BREAK1
↑↑ Escape to the top level
> [->] expr After an error, use expr for the erring atom
FROM?= form Continues by re-evaluating form at LASTPOS
EX Same as FROM?= NIL
USE x FOR y Substitutes x for y in form at LASTPOS
(destructively)
F [&] a1..aN Resets LASTPOS (stack context)
EDIT A1..An Resets LASTPOS and gives the form at LASTPOS
to the LISP Editor
?= f1 ... fN Evaluates forms fI as of LASTPOS
ARGS Prints arguments of the broken function
BKF Backtrace Function Names
BKE Backtrace Function Calls
BK Backtrace Expressions
Note: All of the backtrace commands can be combined with a
'V' or followed by an integer. The 'V' will cause the
values of variables to be printed. The integer will limit
1 . 25
the trace to that number of blocks. For example, BK 3,
BKEV, BKFV 5 and BKEV are all legitimate commands.
1 . 26
2.1 The LISP Editor
Contents
2 CURRENT EXPRESSION, P, &, PP, EDIT CHAIN, 0, ↑,
5 (n), (n e1, ..., em), (-n e1, ..., em), N, F, R, NX, RI,
10 UNDO, BK, BF, <, <P, &, --, @ (AT-SIGN),
13 UP, B, A, :, DELETE, MBD, XTR, UP, ..., n, -n,
18 0, !0, ↑, NX, BK, (NX n), (BK n), !NX, (NTH n),
22 PATTERN MATCH, &, *ANY*, --, ==, ...,
24 SEARCH ALGORITHM, MAXLEVEL, UNFIND, F, (F pat n),
27 (F pat T), (F pat N), (F pat), FS, F=, ORF, BF, (BF pat T),
30 LOCATION SPECIFICATION, IF, ##, $, LC, LCL, SECOND, THIRD,
32 (← pat), BELOW, NEX, (NTH $), .., MARK, ←, ←←, <, UNFIND,
37 <P, S, (n), (n e1, ..., em), (-n e1, ..., em), N,
41 B, A, :, DELETE, INSERT, REPLACE, DELETE, ##, UPFINDFLG,
46 XTR, EXTRACT, MBD, EMBED, MOVE, BI, BO, LI, LO, RI, RO,
57 THRU, TO, R, SW, P, ?, E, I, ##, COMS, COMSQ,
66 IF, LP, LPQ, ORR, MACROS, M, BIND, USERMACROS,
71 NIL, TTY:, OK, STOP, SAVE, REPACK, MAKEFN,
76 UNDO, TEST, ??, !UNDO, UNBLOCK, EDITDEFAULT, EDITL,
81 EDITF, EDITE, EDITV, EDITP, EDITFNS, EDIT4E,
84 EDITFPAT, EDITFINDP
The LISP editor allows rapid, convenient modification
of list structures. Most often it is used to edit function
definitions, (often while the function itself is running)
via the function EDITF, e.g., (EDITF FOO). However, the
editor can also be used to edit the value of a variable, via
EDITV, to edit special properties of an atom, via EDITP, or
to edit an arbitrary expression, via EDITE. It is an
important feature which allows good on-line interaction in
the UCI LISP system.
This chapter begins with a lengthy introduction
intended for the new user. The reference portion begins on
page 15.
2 . 1
Introduction
Let us introduce some of the basic editor commands, and
give a flavor for the editor's language structure by guiding
the reader through a hypothetical editing session. Suppose
we are editing the following incorrect definition of APPEND
(LAMBDA(X)
Y
(COND ((NUL X) Z)
(T (CONS (CAR) (APPEND (CDR X Y))))))
We call the editor via the function EDITF:
#(EDITF APPEND)
EDIT
#
The editor responds by typing EDIT followed by #, which is
the editor's ready character, i.e., it signifies that the
editor is ready to accept commands. (In other words, all
lines beginning with # were typed by the user, the rest by
the editor.)
At any given moment, the editor's attention is centered
on some substructure of the expression being edited. This
substructure is called the current expression, and it is
what the user sees when he gives the editor the command P,
for print. Initially, the current expression is the top
level one, i.e., the entire expression being edited. Thus:
#P
(LAMBDA (X) Y (COND & &))
#
Note that the editor prints the current expression,
using PRINTLEV, to a depth of 2, i.e., sublists of sublists
are printed as &. The command ? Will print the current
expression as though PRINTLEV was given a depth of 100.
#?
(LAMBDA (X) Y (COND ((NUL X) Z) (T (CONS (CAR) (APPEND (CDR
X Y))))))
#
and the command PP (for PrettyPrint) will GRINDEF the
current expression.
2 . 2
A positive integer is interpreted by the editor as a
command to descend into the correspondingly numbered element
of the current expression. Thus:
#2
#P
(X)
#
A negative integer has a similar effect, but counting
begins from the end of the current expression and proceeds
backward, i.e., -1 refers to the last element in the
expression, -2 the next to the last, etc. For either
positive integer or negative integer, if there is no such
element, an error occurs. 'Editor errors' are not the same
as 'LISP errors' , i.e., they never cause breaks or even go
through the error machinery but are direct calls to ERR
indicating that a command is in some way faulty. What
happens next depends on the context in which the command was
being executed. For example, there are conditional commands
which branch on errors. In most situations, though, an
error will cause the editor to type the faulty command
followed by a ? And wait for more input. In this case, the
editor types the faulty command followed by a ?, and then
another #. The current expression is never changed when a
command causes an error. thus:
#P
(x)
#2
2 ?
#1
#P
X
#
A phrase of the form 'the current expression is
changed' or 'the current expression becomes' refers to a
shift in the editor's ATTENTION, not to a modification of
the structure being edited.
When the user changes the current expression by
descending into it, the old current expression is not lost.
Instead, the editor actually operates by maintaining a chain
of expressions leading to the current one. The current
expression is simply the last link in the chain. Descending
adds the indicated subexpression onto the end of the chain,
thereby making it be the current expression. The command 0
2 . 3
is used to ascend the chain; it removes the last link of the
chain, thereby making the previous link be the current
expression. Thus:
#P
X
#0 P
(X)
#0-1 P
(COND (& Z) (T &))
#
Note the use of several commands on a single line in the
previous output. The editor operates in a line buffered
mode. Thus no command is actually seen by the editor, or
executed until the line is terminated, either by a carriage
return, or an escape (alt-mode).
In our editing session, we will make the following
corrections to APPEND: delete Y from where it appears, add Y
to the end of the argument list, (These two operations could
be thought of as one operation, i.e., move Y from its
current position to a new position, and in fact there is a
MOVE command in the editor. However, for the purposes of
this introduction, we will confine ourselves to the simpler
edit commands.) change NUL to NULL, change Z to Y, add X
after CAR, and insert a right parenthesis following CDR X.
First we will delete Y. By now we have forgotten where
we are in the function definition, but we want to be at the
"top," so we use the command ↑, which ascends through the
entire chain of expressions to the top level expression,
which then becomes the current expression, i.e., ↑ removes
all links except the first one.
#↑ P
(LAMBDA (X) Y (COND & &))
#
Note that if we are already at the top, ↑ has no
effect, i.e., it is a NOP. However, 0 would generate an
error. In other words, ↑ means "go to the top," while 0
means "ascend one link."
2 . 4
The basic structure modification commands in the editor
are
(n)
n>1 deletes the corresponding
element from the current expression.
(n e1,...,em)
n,m>1 replaces the nth element in
the current expression with
e1,...,em.
(-n e1,...,em)
n,m>1 inserts e1,...,em before the
nth element in the current
expression.
Thus:
#P
(LAMBDA (X) Y (COND & &))
#(3)
#(2 (X Y))
#P
(LAMBDA (X Y) (COND & &))
#
All structure modification done by the editor is
destructive, i.e., the editor uses RPLACA and RPLACD to
physically change the structure it was given. Note that all
three of the above commands perform their operation with
respect to the nth element from the front of the current
expression; the sign of n is used to specify whether the
operation is replacement or insertion. Thus, there is no
way to specify deletion or replacement of the nth element
from the end of the current expression, or insertion before
the nth element from the end without counting out that
element's position from the front of the list. Similarly,
because we cannot specify insertion after a particular
element, we cannot attach something at the end of the
current expression using the above commands. Instead, we
use the command N (for NCONC). Thus we could have performed
the above changes instead by:
2 . 5
#P
(LAMBDA (X) Y (COND & &))
#(3)
#2 (N Y)
#P
(X Y)
#↑ P
#(LAMBDA (X Y) (COND & &))
#
Now we are ready to change NUL to NULL. Rather than
specify the sequence of descent commands necessary to reach
NULL, and then replace it with NULL, i.e., 3 2 1 (1 NULL),
we will use F, the find command, to find NULL:
#P
(LAMBDA (X Y) (COND & &))
#F NUL
#P
(NUL X)
#(1 NULL)
#0 P
((NULL X) Z)
#
Note that F is special in that it corresponds to TWO
inputs. In other words, F says to the editor, "treat your
next command as an expression to be searched for." The
search is carried out in printout order in the current
expression. If the target expression is not found there, F
automatically ascends and searches those portions of the
higher expressions that would appear after (in a printout)
the current expression. If the search is successful, the
new current expression will be the structure where the
expression was found, (If the search is for an atom, e.g., F
NUL, the current expression will be the structure containing
the atom. If the search is for a list, e.g., F (NUL X), the
current expression will be the list itself.) and the chain
will be the same as one resulting from the appropriate
sequence of ascent and descent commands. If the search is
not successful, an error occurs, and neither the current
expression nor the chain is changed: (F is never a NOP,
i.e., if successful, the current expression after the search
will never be the same as the current expression before the
search. Thus F EXPR repeated without intervening commands
that change the edit chain can be used to find successive
instances of EXPR.)
2 . 6
#P
((NULL X) Z)
#F COND P
COND ?
#P
#((NULL X) Z)
#
Here the search failed to find a COND following the
current expression, although of course a COND does appear
earlier in the structure. This last example illustrates
another facet of the error recovery mechanism: to avoid
further confusion when an error occurs, all commands on the
line beyond the one which caused the error (and all commands
that may have been typed ahead while the editor was
computing) are forgotten.
We could also have used the R command (for Replace) to
change NUL to NULL. A command of the form (R e1 e2) will
replace all occurrances of e1 in the current expression by
e2. There must be at least one such occurrence or the R
command will generate an error. Let us use the R command to
change all Z's (even though there is only one) in APPEND to
Y:
#↑ (R Z Y)
#F Z
Z ?
#PP
(LAMBDA(X Y)
(COND ((NULL X) Y)
(T (CONS (CAR) (APPEND (CDR X Y))))))
#
The next task is to change (CAR) to (CAR X). We could
do this by (R (CAR) (CAR X)), or by:
#F CAR
#(N X)
#P
(CAR X)
#
The expression we now want to change is the next
expression after the current expression, i.e., we are
2 . 7
currently looking at (CAR X) in (CONS (CAR X) (APPEND (CDR X
Y))). We could get to the APPEND expression by typing 0 and
then 3 or -1, or we can use the command NX, which does both
operations:
#P
(CAR X)
#NX P
(APPEND (CDR X Y))
#
Finally, to change (APPEND (CDR X Y)) to (APPEND (CDR
X) Y), we could perform (2 (CDR X) Y), or (2 (CDR X)) and (N
Y), or 2 and (3), deleting the Y, and then 0 (N Y).
However, if Y were a complex expression we would not want to
have to retype it. Instead, we could use a command which
effectively inserts and/or removes left and right
parentheses. There are six of these BI, BO, LI, LO, RI, and
RO, for Both In, Both Out, Left In, Left Out, Right In, and
Right Out. Of course, we will always have the same number
of left parentheses as right parentheses, because the
parentheses are just a notational guide to structure that is
provided by our print program. (Herein lies one of the
principal advantages of a LISP oriented editor over a text
editor: unbalanced parentheses errors are not possible.)
Thus, left in, left out, right in, and right out actually do
not insert or remove just one parenthesis, but this is very
suggestive of what actually happens.
In this case, we would like a right parenthesis to
appear following X in (CDR X Y). Therefore, we use the
command (RI 2 2), which means insert a right parentheses
after the second element in the second element (of the
current expression):
#P
(APPEND (CDR X Y))
#(RI 2 2)
#P
(APPEND (CDR X) Y)
#
We have now finished our editing, and can exit from the
editor, to test APPEND, or we could test it while still
inside of the editor, by using the E command:
#E (APPEND (QUOTE (A B)) (QUOTE (C D E)))
(A B C D E)
2 . 8
The E command causes the next input to be given to
EVAL.
We GRINDEF APPEND, and leave the editor.
#PP
(LAMBDA(X Y)
(COND ((NULL X) Y)
(T (CONS (CAR X) (APPEND (CDR X) Y)))))
#OK
APPEND
*
2 . 9
2.10 Commands for the New User
This manual is intended primarily as a reference
manual, and the remainder of this chapter is organized and
presented accordingly. While the commands introduced in the
previous scenario constitute a complete set, i.e., the user
could perform any and all editing operations using just
those commands, there are many situations in which knowing
the right command(s) can save the user considerable effort.
We include here as part of the introduction a list of those
commands which are not only frequently applicable but also
easy to use. They are not presented in any particular
order, and are all discussed in detail in the reference
portion of the chapter.
UNDO
Undoes the last modification to the
structure being edited, e.g., if the
user deletes the wrong element, UNDO
will restore it. The availability
of UNDO should give the user
confidence to experiment with any
and all editing commands, no matter
how complex, because he can always
reverse the effect of the command.
BK
Like NX, except makes the expression
immediately before the current
expression become current.
BF
Backwards Find. Like F, except
searches backwards, i.e., in inverse
print order.
<
Restores the current expression to
the expression before the last "big
jump", e.g., a find command, an ↑,
or another <. For example, if the
user types F COND, and then F CAR, <
would take him back to the COND.
Another < would take him back to the
CAR.
2 . 10
<P
Like < except it restores the edit
chain to its state as of the last
print, either by P, ?, or PP. If
the edit chain has not been changed
since the last print, <P restores it
to its state as of the printing
before that one, i.e., two chains
are always saved.
Thus if the user types P followed by 3 2 1 P, <P will
take him back to the first P, i.e., would be equivalent to 0
0 0. Another <P would then take him back to the second P,
i.e., he can use <P to flip back and forth between two
current expressions.
&,--
The search expression given to the F
or BF command need not be a literal
S-expression. Instead, it can be a
pattern. The symbol & can be used
anywhere within this pattern to
match with any single element of a
list, and -- can be used to match
with any segment of a list. Thus,
in the incorrect definition of
APPEND used earlier, F (NUL &) could
have been used to find (NUL X), and
F (CDR --) or F (CDR & &), but not F
(CDR &), to find (CDR X Y).
Note that & and -- can be nested arbitrarily deeply in
the pattern. For example, if there are many places where
the varaible X is set, F SETQ may not find the desired
expression, nor may F (SETQ X &). It may be necessary to use
F (SETQ X (LIST --)). However, the usual technique in such a
case is to pick out a unique atom which occurs prior to the
desired expression and perform two F commands. This "homing
in" process seems to be more convenient than ultra-precise
specification of the pattern.
2 . 11
@ (at-sign)
Any atom ending in @ (at-sign) in a
pattern will match with the first
atom or string that contains the
same initial characters. For
example, F VER@ will find
VERYLONGATOM. @ can be nested inside
of the pattern, e.g., F (SETQ VER@
(CONS --)).
If the search is successful, the
editor will print = followed by the
atom which matched with the @-atom,
e.g.,
#F (SETQ VER@ &)
=VERYLONGATOM
#
Frequently the user will want to replace the entire
current expression or insert something before it. In order
to do this using a command of the form (n e1,...,em) or (-n
e1,...,em), the user must be above the current expression.
In other words, he would have to perform a 0 followed by a
command with the appropriate number. However, if he has
reached the current expression via an F command, he may not
know what that number is. In this case, the user would like
a command whose effect would be to modify the edit chain so
that the current expression became the first element in a
new, higher current expression. Then he could perform the
desired operation via (1 e1,...,em) or (-1 e1,...,em). UP
is provided for this purpose.
2 . 12
UP
After UP operates, the old current
expression is the first element of
the new current expression. Note
that if the current expression
happens to be the first element in
the next higher expression, then UP
is exactly the same as 0.
Otherwise, UP modifies the edit
chain so that the new current
expression is a tail (Throughout
this chapter 'tail' means 'proper
tail') of the next higher
expression:
#F APPEND
(APPEND (CDR X) Y)
#UP P
... (APPEND & Y))
#0 P
(CONS (CAR X) (APPEND & Y))
#
The ... is used by the editor to
indicate that the current expression
is a tail of the next higher
expression as opposed to being an
element (i.e., a member) of the next
higher expression. Note: if the
current expression is already a
tail, UP has no effect.
(B e1,...,em)
Inserts e1,...,em before the current
expression, i.e., does an UP and
then a -1.
(A e1,...,em)
Inserts e1,...,em after the current
expression, i.e., does an UP and
then either a (-2 e1,...,em) or an
(N e1,...,em), if the current
expression is the last one in the
next higher expression.
2 . 13
(: e1,...,em)
Replaces current expression by
e1,...,em, i.e., does an UP and then
a (1 e1,...,em).
DELETE
Deletes current expression, i.e.,
equivalent to (:).
Earlier, we introduced the RI command in the APPEND
example. The rest of the commands in this family:, BI, RO,
LI, LO, and RO, perform similar functions and are useful in
certain situations. In addition, the commands MBD and XTR
can be used to combine the effects of several commands of
the BI-BO family. MBD is used to embed the current
expression in a larger expression. For example, if the
current expression is (PRINT bigexpression), and the user
wants to replace it by (COND (FLG (PRINT bigexpression))),
he can acomplish this by (LI 1), (-1 FLG), (LI 1), and (-1
COND), or by a single MBD command.
XTR is used to extract an expression from the current
expression. For example, extracting the PRINT expression
from the above COND could be accomplished by (1), (LO 1),
and (LO 1) or by a single XTR command. The new user is
encouraged to include XTR and MBD in his repertoire as soon
as he is familiar with the more basic commands.
2 . 14
1↓↓α↓απS&+;S'}qα∂#∞s∨';:α∂?7n;∪LhP4)↓α↓↓↓↓α↓↓α∂}k7π;'→↓βSz↓βS#*↓β↔∪O#?I↓αβ≠π3b↓β';&y↓βSG∪↔∃↓ε≠3πO≡+Mh4R↓↓↓↓ε≠?77∞s∪Mβ&CπQβ≡Cπ;∨*βS#∃αβ∂WK⊗+;Q↓ε+cCK/≠O'?r↓↓#%v)91β≡Cπ;∨(h)↓↓α↓βS#*↓β↔∪O!β∂#∞K9%↓π##↔K.∪e↓≡C'≠SNs≥βSF)β↔∪O#?I∨~βπSS.sS'?raλ4)α↓↓↓β≡{77πv#M↓↓π##πQαβ7?∪N3e↓β&C∃↓β∨#KW∂'+K∃↓ε∪↔';:↓β↔∪O#↔⊃1αβπ;⊂hQ↓↓↓αβ7'O≡+33πv+?WMαβ∂?7n;∪Mb↓β∃;:q1↓β/C'S'v9↓β≠⊗{5↓β&C∃↓β.#'S?∩`4)↓α↓↓βC⊗K;S'v91β↔63Wπ&K;≥β/CCK↔∨≠'?;~q4)α↓↓↓↓α↓↓↓β>KS#'rβS#∃αβ∂?;&+cQβ}1β∂?nkπ;∪~βS#π"βO#'7!βS#*β↔∪'&{I∨LhQ↓↓↓αβπSS.sS'?raβ←∃ε≠π9β&KOS'v;W'OBβπ7?v9↓!EJβS#?≡)β∂?nkπ;∪~β←#?≡(4)↓α↓↓β?ε+KπSN{9↓β&+C↔;'→↓β?vceβ?rβS#∃π≠SKW∨#WK∃ε{→βSF)β↔∪O!β∂#∞K904R↓↓↓↓ε);≥9b↓↓A1ααVA1∧ram↓C⊃%βSF{O∃β>C'∂!ε#↔C↔v!β?9π##∃β≡{;S↔w#Mβ?0h)↓↓α↓βS#*βOSK.≠SWK*a↓β%v)91↓ε≠?77∞s∪Mβ&CπQ↓π≠↔πK≡Am↓β∞s⊃↓!~IβS#␈≠∀4)α↓↓↓β≡{77πv#M↓β>C'∂!αβO'7εce↓β⊗+OS?⊗)↓βSF)↓β↔&KQ↓β≡Cπ'9αβS=↓π≠?7∀hQ↓↓↓αβCK↔6K?WMπ≠SπS*a↓β∃v991↓βa1↓↓e↓9↓↓αAE%↓αβπ;⊃α↓!I%ε≠π9β∞cO=β⊗(4)↓α↓↓βSF{W∨#"β?→↓εM↓βf{∂π1b↓βO7∞c1βO&+CM↓π3↔KO/→↓β?ε+9β↔v#↔⊃1ε∪'≤4R↓↓↓↓εSW7C~q↓↓↓∧≠?77∞s∪M↓ε{→↓β'KC∃↓αAE%↓αβπK∃α↓β∪'≡≠WOO.!↓β?r↓βCAr4)↓α↓↓↓Is U5Is⊃Em↓π#gC∃αAI%β}qβCAr↓↓I9∪⊃5I9≠)m↓β∞s⊃βSOβ∃↓!~Iβ?9πβA84R↓↓↓↓β⊃9MYk⊃9M]r4(4Ph(4(hP4(4Ph(4(hP4(4Ph(4(hP4(4Ph(4(hP4(4Ph(4(hP4(4Ph(4(hP4(4Ph(4)α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓I↓r↓ET4Ph(1↓↓α↓α3?≡1απ'#↔;SN{96∂F;∨'v9α∂?nkπ;∪_h(4)α↓↓↓α-4)↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓!EJ↓α'→ε αA↓ε≠?77∞s⊃β←␈+3⊃β≡WO∃π##∀4R↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓β.#'S?∩βS=↓π#gC∃α↓999α↓β↔6{K∃β'KC';8h)↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓αβS#∃αβ∂WK⊗+;Q↓ε+cCK/≠O'?ra↓β%v)91β&C∀4)α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓β∂/∪K↔;"↓β↔cπ∪↔OON{9β'~β¬βS∞K1β?2βS#∀hQ↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓εs↔cQαβ#'∨F+Iβ↔GβK↔O≡K?91ααVA↓εCπMβvx4)↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓β↔≠6+∂Qmε{S#↔↔;'O∀hQ↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓αAI%↓¬*A↓βn{∪'≠N+M↓β&C∃β↔&KQβ∂F'9β≡x4)↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓βS#∂!↓βSF)↓β?f!↓↓β∨+KK↔w!↓β↔GβK↔O≡K?84R↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓FI;∃9b↓βS#*β?;∃αβπQ↓π##∃β&K7∃α-↓β←π_h)↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓αβ∂π3f+⊃%↓εKMβSF)β≠'↔≠Qβ↔f+7↔;"β'9β&C∀4)α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓β;/9↓β∂/∪K↔;"↓β↔cπ∪↔OON{99↓α↓"'→αβS#∀hQ↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓ε≠WKK.sQ↓β/CCK↔∨≠'?9αβ'M↓αβS#∃αβ≠'K∨ 4)↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓β↔3.k↔;Qα↓↓β'r↓↓βSF)↓↓↓εs↔cQα↓β#'>C↔H4R↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓β/CCK↔∨≠'?9α↓αVAαβO'7εce↓β&{↔M↓ε ↓↓Ar4)↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓α?SF+K←'≡)αVAαβπ∪∪~βS#∃ε≠?KK/≠C?;&K;≤4R↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓β&'1β&yβS#*β↔∪'"β∂#πNq94Ph)↓↓α↓↓↓↓α↓α↔c∞kC3↔≠Q↓αSF)β∂W↔∪↔;Qε+cCK/≠O'?rβ'9β.∂!β≡O∃βO→↓"∞|r⊂4)α↓↓↓↓BB:V2bαa%↓E∩⊗RV∀qαe%JI84(hQ↓↓↓α↓↓↓↓α↓↓↓↓α↓E9↓α↓↓↓↓≠ α@4R↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓α∞|r⊂4)α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓∞Vαα@4)α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓"∞|r⊃↓!2↓→%$hP4)↓α↓↓↓↓α↓↓↓↓α↓↓↓Ir↓↓↓↓α↓
5E¬4)↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓!":,b1αaJ↓"J⊗%*J9αJI$4)α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓∞Vαα@4)α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓99r↓!":,b1αaJ↓"J⊗%*J9αJI%$4R↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓∞-↓α@4R↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓9rq↓!"u*21αBI↓"J-"VJ9¬I%%$hP4)↓α↓↓↓↓α↓↓↓↓α↓↓↓Mr↓↓↓↓α↓∞→αu*21αh)↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓αB:V2bαa$4R↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓∞-↓α@4R↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓!DrV21¬A%↓"∀*RVJrαe%$hQ↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓≥*Aα@hQ↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓rq9↓!DrV21¬A%↓"∀*RVJrαe%%Hh(4)α↓↓↓↓α↓↓↓α&C∃β↔F+∂WSN{9β?2αVAβO→βOS⊗'∨#&3?K←∂∪⊃1β/C∂↔C"β'9β&C?O∀hQ↓↓↓αβ∂πO/→β←#/∪∃βSF)β∂W↔∪↔;Qε+cCK/≠O'?rβπCC.KMβn{K∃β&Cπ9β}s∂∃βNp4)↓α↓↓βSF)↓β;/CQβ#N;#↔Iε+cCK/≠O'?rq↓↓α6{Iβ↔F7C3*a↓β'2↓βS#*β∂WK⊗+;P4R↓↓↓↓ε+cCK/≠O'?rβ'M↓D ↓α:Laα αtJ1↓α~α:&1J↓βπ;"βS#∃π+O↔Iπβ↔K≠␈∪7M↓ h)↓↓α↓β≠?fc?←↔"βe↓¬*A1↓π##∃β∨+KK↔w!β↔cπ∪↔OON{9βOF{W3⊃αβS#↔be ...
NIL C NIL.) UP can determine which tail is the correct one
2 . 16
because the commands that descend save the last tail on an
internal editor variable, LASTAIL. Thus after the 4 command
is executed, LASTAIL is (NIL C NIL). When UP is called, it
first determines if the current expression is a tail of the
next higher expression. If it is, UP is finished.
Otherwise, UP computes
(MEMB current-expression next-higher-expression) to obtain a
tail beginning with the current expression. (The current
expression should always be either a tail or an element of
the next higher expression. If it is neither, for example
the user has directly (and incorrectly) manipulated the edit
chain, UP generates an error.) If there are no other
instances of the current-expression in the next higher
expression, this tail is the correct one. Otherwise UP uses
LASTAIL to select the correct tail. (Occasionally the user
can get the edit chain into a state where LASTAIL cannot
resolve the ambiguity, for example if there were two
non-atomic structures in the same expression that were EQ,
and the user descended more than one level into one of them
and then tried to come back out using UP. In this case, UP
selects the first tail and prints LOCATION UNCERTAIN to warn
the user. Of course, we could have solved this problem
completely in our implementation by saving at each descent
both elements and tails. However, this would be a costly
solution to a situation that arises infrequently, and when
it does, has no detrimental effects. The LASTAIL solution
is cheap and resolves 99% of the ambiguities.
n (n>0)
Adds the nth element of the current
expression to the front of the edit
chain, thereby making it be the new
current expression. Sets LASTAIL
for use by UP. Generates an error
if the current expression is not a
list that contains at least n
elements.
-n (n>0)
Adds the nth element from the end of
the current expression to the front
of the edit chain, thereby making it
be the new current expression. Sets
LASTAIL for use by UP. Generates an
error if the current expression is
not a list that contains at least n
elements.
2 . 17
0
Sets edit chain to CDR of edit
chain, thereby making the next
higher expression be the new correct
expression. Generates an error if
there is no higher expression, i.e.,
CDR of edit chain is NIL.
Note that 0 usually corresponds to going back to the next
higher left parenthesis, but not always. For example, if
the current expression is (A B C D E F G), and the user
performs
# UP P
... C D E F G)
#3 UP P
... E F G)
#0 P
... C D E F G)
If the intention is to go back to the next higher left
parenthesis, regardless of any intervening tails, the
command !0 can be used. (!0 is pronounced bang-zero.)
!0
Does repeated 0's until it reaches a
point where the current expression
is not a tail of the next higher
expression, i.e., always goes back
to the next higher left parenthesis.
↑
Sets edit chain to LAST of edit
chain, thereby making the top level
expression be the current
expression. Never generates an
error.
2 . 18
NX
Effectively does an UP followed by a
2, (Both NX and BK operate by
performing a !0 followed by an
appropriate number, i.e. There
won't be an extra tail above the new
current expression, as there would
be if NX operated by performing an
UP followed by a 2.) thereby making
the current expression be the next
expression. Generates an error if
the current expression is the last
one in a list. (However, !NX
described below will handle this
case.)
BK
Makes the current expression be the
previous expression in the next
higher expression. Generates an
error if the current expression is
the first expression in a list.
For example, if the current expression is (COND ((NULL X)
(RETURN Y)))
#F RETURN P
(RETURN Y)
#BK P
(NULL X)
(NX n) n>0
Equivalent to n NX commands, except
if an error occurs, the edit chain
is not changed.
(BK n) n>0
Equivalent to n BK commands, except
if an error occurs, the edit chain
is not changed.
Note: (NX -n) is equivalent to (BK n), and vice versa.
2 . 19
2.20 !NX
Makes current expression be the next
expression at a higher level, i.e.,
goes through any number of right
parentheses to get to the next
expression.
For example:
#PP
(PROG (UF)
(SETQ UF L)
LP (COND ((NULL (SETQ L (CDR L))) (ERR NIL))
((NULL (CDR (MEMQ# (CAR L) (CADR L))))
(GO LP)))
(EDITCOM (QUOTE NX))
(SETQ UNFIND UF)
(RETURN L))
#F CDR P
(CDR L)
#NX
NX ?
#!NX P
(ERR NIL)
#NX P
((NULL &) (GO LP))
#!NX P
(EDITCOM (QUOTE NX))
#
!NX operates by doing 0's until it reaches a stage
where the current expression is not the last expression in
the next higher expression, and then does a NX. Thus !NX
always goes through at least one unmatched right
parenthesis, and the new current expression is always on a
different level, i.e., !NX and NX always produce different
results. For example using the previous current expression:
2 . 20
#F CAR P
(CAR L)
#!NX P
(GO LP)
#<P P
(CAR L)
#NX P
(CADR L)
#
(NTH n) n>0
Equivalent to n followed by UP,
i.e., causes the list starting with
the nth element of the current
expression. ((NTH 1) is a NOP.)
Causes an error if current
expression does not have at least n
elements.
A generalized form of NTH using location specifications is
described on page 2.34.
2 . 21
Commands That Search
All of the editor commands that search use the same
pattern matching routine. (This routine is available to the
user directly, and is described later in this chapter in the
section on "Editor Functions.") We will therefore begin our
discussion of searching by describing the pattern match
mechanism. A pattern PAT matches with X if
1. PAT is EQ to X.
2. PAT is &.
3. PAT is a number and EQUAL to X.
4. If (CAR pat) is the atom *ANY*, (CDR pat) is a
list of patterns, and PAT matches X if and only
if one of the patterns on (CDR pat) matches X.
5. If PAT is a literal atom or string, and (NTHCHAR
pat -1) is @, then PAT matches with any literal
atom or string which has the same initial
characters as PAT, e.g. VER@ matches with
VERYLONGATOM, as well as "VERYLONGSTRING".
6. If (CAR pat) is the atom --, PAT matches X if
A. (CDR pat)=NIL, i.e. PAT=(--),
e.g., (A --) matches (A) (A B C) and
(A . B)
In other words, -- can match any tail of
a list.
B. (CDR pat) matches with some tail of X,
e.g. (A -- (&)) will match with (A B
C (D)), but not (A B C D), or (A B C
(D) E). However, note that (A -- (&)
--) will match with (A B C (D) E).
In other words, -- will match any
interior segment of a list.
7. If (CAR pat) is the atom ==, PAT matches X if
and only if (CDR pat) is EQ to X. (This pattern
is for use by programs that call the editor as a
subroutine, since any non-atomic expression in a
command type in by the user obviously cannot be
EQ to existing structure.)
8. Otherwise if X is a list, PAT matches X if (CAR
pat) matches (CAR x), and (CDR pat) matches (CDR
x).
When searching, the pattern matching routine is called
only to match with elements in the structure, unless the
pattern begins with :::, in which case CDR of the pattern is
matched against tails in the structure. (In this case, the
tail does not have to be a proper tail, e.g. (::: A --)
2 . 22
will match with the element (A B C) as well as with CDR of
(X A B C), since (A B C) is a tail of (A B C).) Thus if the
current expressiion is (A B C (B C)),
#F (B --)
#P
(B C)
#0 F (::: B --)
#P
... B C (B C))
#F (::: B --)
#P
(B C)
#
2 . 23
Search Algorithm
Searching begins with the current expression and
proceeds in print order. Searching usually means find the
next instance of this pattern, and consequently a match is
not attempted that would leave the edit chain unchanged.
(However, there is a version of the find command which can
succeed and leave the current expression unchanged.) At each
step, the pattern is matched against the next element in the
expression currently being searched, unless the pattern
begins with ::: in which case it is matched against the
corresponding tail of the expression. (EQ pattern
tail-of-expression)=T also indicates a successful match, so
that a search for FOO will find the FOO in (FIE . FOO).
The only exception to this occurs when PATTERN=NIL, e.g., F
NIL. In this case, the pattern will not match with a null
tail (since most lists end in NIL) but will match with a NIL
element.
If the match is not successful, the search operation is
recursive first in the CAR direction and then in the CDR
direction, i.e., if the element under examination is a list,
the search descends into that list before attempting to
match with other elements (or tails) at the same level.
(There is also a version of the find command which only
attempts matches at the top level of the current expression,
i.e., does not descend into elements, or ascend to higher
expressions.)
However, at no point is the total recursive depth of
the search (sum of number of CARs and CDRs descended into)
allowed to exceed the value of the variable MAXLEVEL. At
that point, the search of that element or tail is abandoned,
exactly as though the element or tail had been completely
searched without finding a match, and the search continues
with the next element or tail for which the recursive depth
is below MAXLEVEL. This feature is designed to enable the
user to search circular list structures (by setting MAXLEVEL
small), as well as protecting him from accidentally
encountering a circular list structure in the course of
normal editing. MAXLEVEL is initially set to 300. If a
successful match is not found in the current expression, the
search automatically ascends to the next higher expression,
and continues searching there on the next expression after
the expression it just finished searching. If there is
none, it ascends again, etc. This process continues until
the entire edit chain has been searched, at which point the
search fails, and an error is generated. If the search
2 . 24
fails the edit chain is not changed (nor are any CONSes
performed.)
If the search is successful, i.e., an expression is
found that the pattern matches, the edit chain is set to the
value it would have had had the user reached that expression
via a sequence of integer commands.
If the expression that matched was a list, it will be
the final link in the edit chain, i.e., the new current
expression. If the expression that matched is not a list,
e.g., is an atom, the current expression will be the tail
beginning with that atom, (Except for situations where match
is with Y in (X . Y), Y atomic and not NIL. In this case,
the current expression will be (X . Y).) i.e., that atom
will be the first element in the new current expression. In
other words, the search effectively does an UP. (Unless
UPFINDFLG=NIL (initially set to T). For discussion, see
page 2.45).
2 . 25
Search Commands
All of the commands below set LASTAIL for use by UP,
set UNFIND for use by < (p. 2.36), And do not change the
edit chain or perform any CONSes if they are unsuccessful or
aborted.
F pattern
i.e., two commands: the F informs
the editor that the next command is
to be interpreted as a pattern.
This is the most common and useful
form of the find command. If
successful, the edit chain always
changes, i.e., F pattern means find
the next instance of PATTERN.
If (MEMB pattern current-expression)
is true, F does not proceed with a
full recursive search.
If the value of the MEMB is NIL, F
invokes the search algorithm
described earlier.
Thus if the current expression were (PROG NIL LP (COND
(--(GO LP1))) ... LP1 ...), F LP1 would find the prog
label, not the LP1 inside of the GO expression, even though
the latter appears first (in print order) in the current
expression. Note that 1 (making the atom PROG be the
current expression), followed by F LP1 would find the first
LP1.
(F pattern N)
Same as F pattern, i.e., finds the
next instance of pattern, except the
MEMB check of F pattern is not
performed.
2 . 26
(F pattern T)
Similar to F pattern, except may
succeed without changing edit chain,
and does not perform the MEMB check.
Thus if the current expression is (COND ..), F COND
will look for the next COND, but (F COND T) will 'stay
here'.
(F pattern n) n>0
Finds the nth place that pattern
matches. Equivalent to (F pattern
T) followed by (F pattern N)
repeated n-1 times. Each time
PATTERN successfully matches, n is
decremented by 1, and the search
continues, until n reaches 0. Note
that the pattern does not have to
match with n identical expressions;
it just has to match N times. Thus
if the current expression is (FOO1
FOO2 FOO3), (F F00@ 3) will find
FOO3.
If the pattern does not match
successfully N times, an error is
generated and the edit chain is
unchanged (even if the PATTERN
matched n-1 times).
(F pattern) or
(F pattern NIL)
Only matches with elements at the
top level of the current expression,
i.e., the search will not descend
into the current expression, nor
will it go outside of the current
expression. May succeed without
changing edit chain.
For example, if the current expression is
(PROG NIL (SETQ X (COND & &)) (COND &) ...)
F (COND --) will find the COND inside the SETQ, whereas (F
(COND --)) will find the top level COND, i.e., the second
one.
2 . 27
(FS pattern[1] ... pattern[n])
Equivalent to F pattern[1] followed
by F pattern[2] ... followed by F
pattern n, so that if F pattern m
fails, edit chain is left at place
pattern m-1 matched.
(F= expression x)
Equivalent to (F (== . Expression)
x), i.e., searches for a structure
EQ to expression, see p. 2.22.
(ORF pattern[1] ... pattern[n])
Equivalent to (F (*ANY* pattern[1]
... pattern[n]) N), i.e., searches
for an expression that is matched by
either pattern[1] or ...
pattern[n]. See p. 2.22.
BF pattern
Backwards Find. Searches in reverse
print order, beginning with
expression immediately before the
current expression (unless the
current expression is the top level
expression, in which case BF
searches the entire expression, in
reverse order.)
BF uses the same pattern match
routine as F, and MAXLEVEL and
UPFINDFLG have the same effect, but
the searching begins at the end of
each list, and descends into each
element before attempting to match
that element. If unsuccessful, the
search continues with the next
previous element, etc., until the
front of the list is reached, at
which point BF ascends and backs up,
etc.
For example, if the current expression is
(PROG NIL (SETQ X (SETQ Y (LIST Z))) (COND ((SETQ W --) --)) --)
F LIST followed by BF SETQ will leave the current
expression as (SETQ Y (LIST Z)), as will F COND followed by
BF SETQ
2 . 28
(BF pattern T)
Search always includes current
expression, i.e., starts at end of
current expression and works
backward, then ascends and backs up,
etc.
Thus in the previous example, where F COND followed by
BF SETQ found (SETQ Y (LIST Z)), F COND followed by (BF SETQ
T) would find the (SETQ W --) expression.
(BF pattern) Same as BF pattern.
(BF pattern NIL)
2 . 29
2.30 Location Specification
Many of the more sophisticated commands described later
in this chapter use a more general method of specifying
position called a LOCATION SPECIFICATION. A LOCATION
SPECIFICATION is a list of edit commands that are executed
in the normal fashion with two exceptions. First, all
commands not recognized by the editor are interpreted as
though they had been preceded by F. (Normally such commands
would cause errors.) For example, the location specification
(COND 2 3) specifies the 3rd element in the first clause of
the next COND. (Note that the user could always write (F
COND 2 3) for (COND 2 3) if he were not sure whether or not
COND was the name of an atomic command.)
Secondly, if an error occurs while evaluating one of
the commands in the location specification, and the edit
chain had been changed, i.e., was not the same as it was at
the beginning of that execution of the location
specification, the location operation will continue. In
other words, the location operation keeps going unless it
reaches a state where it detects that it is 'looping', at
which point it gives up. Thus, if (COND 2 3) is being
located, and the first clause of the next COND contained
only two elements, the execution of the command 3 would
cause an error. The search would then continue by looking
for the next COND. However, if a point were reached where
there were no further CONDs, then the first command, COND,
would cause the error; the edit chain would not have been
changed, and so the entire location operation would fail,
and cause an error.
The IF command and the ## function provide a way of
using in location specifications arbitrary predicates
applied to elements in the current expression. IF and ##
will be described in detail later in the chapter, along with
examples ilustrating their use in location specifications.
Throughout this chapter, the meta-symbol $ is used to
denote a location specification. Thus $ is a list of
commands interpreted as described above. $ Can also be
atomic, in which case it is interpreted as (LIST $).
2 . 30
(LC . $)
Provides a way of explicitly
invoking the location operation,
e.g. (LC COND 2 3) will perform the
search described above.
(LCL . $)
Same as LC except search is confined
to current expression, i.e., the
edit chain is rebound during the
search so it looks as if the editor
were called on just the current
expression. For example, to find a
COND containing a RETURN, one might
use the location specification (COND
(LCL RETURN) <) where the < would
reverse the effects of the LCL
command, and make the final current
expression be the COND.
(SECOND . $)
Same as (LC . $) Followed by
another (LC . $) Except that if
the first succeeds and second fails,
no change is made to the edit chain.
(THIRD . $)
Similar to second.
2 . 31
(← pattern)
Ascends the edit chain looking for a
link which matches PATTERN. in other
words, it keeps doing 0's until it
gets to a specified point. If
PATTERN is atomic, it is matched
with the first element of each link,
otherwise with the entire link. (If
pattern is of the form (IF
expression), EXPRESSION is evaluated
at each link, and if its value is
NIL, or the evaluation causes an
error, the ascent continues.)
For example:
#PP
(PROG NIL
(COND ((NULL (SETQ L (CDR L)))
(COND (FLG (RETURN L))))
((NULL (CDR (MEMB (CAR L (CADR L)))))
(GO LP))))
#F CADR
#(← COND)
#P
(COND (& &) (& &))
#
Note that this command differs from BF in that it does
not search inside of each link, it simply ascends. Thus in
the above example, F CADR followed by BF COND would find
(COND (FLG (RETURN L))), not the higher COND.
If no match is found, an error is
generated and the edit chain is
unchanged.
(BELOW com x)
Ascends the edit chain looking for a
link specified by COM, and stops x
links below that, i.e. BELOW keeps
doing 0's until it gets to a
specified point, and then backs off
N 0's. (X is evaluated, e.g.,
(BELOW com (*PLUS X Y)))
2 . 32
(BELOW com)
Same as (BELOW com 1)
For example, (BELOW COND) will cause the COND clause
containing the current expression to become the new current
expression. Thus if the current expression is as shown
above, F CADR followed by (BELOW COND) will make the new
expression be ([NULL (CDR (FMEMB (CAR L) CADR L] (GO LP)),
and is therefore equivalent to 0 0 0 0.
BELOW operates by evaluating X and
then executing COM, or (← com) if
COM is not a recognized edit
command, and measuring the length of
the edit chain at that point. If
that length is M and the length of
the current edit chain is N, then
BELOW ascends n-m-y links where Y is
the value of X. Generates an error
if COM causes an error, i.e., it
can't find the higher link, or if
n-m-y is negative.
The BELOW command is useful for locating a substructure
by specifying something it contains. For example, suppose
the user is editing a list of lists, and wants to find a
sublist that contains a FOO (at any depth). He simply
executes F FOO (BELOW <).
(NEX x)
Same as (BELOW x) followed by NX.
For example, if the user is deep inside of a SELECTQ clause,
he can advance to the next clause with (NEX SELECTQ).
NEX
Same as (NEX ←).
The atomic form of NEX is useful if the user will be
performing repeated executions of (NEX x). By simply
MARKing (see p. 2.36) The chain corresponding to X, he can
use NEX to step through the sublists.
2 . 33
(NTH $)
Generalized NTH command.
Effectively performs (LCL . $),
Followed by (BELOW <), followed by
UP.
In other words, NTH locates $, using a search restricted to
the current expression, and then backs up to the current
level, where the new current expression is the tail whose
first element contains, however deeply, the expression that
was the terminus of the location operation. For example:
#P
(PROG (& &) LP (COND & &) (EDITCOM &) (SETQ UNFIND UF) (RETURN L))
#(NTH UF)
#P
... (SETQ UNFIND UF) (RETURN L))
#
If the search is unsuccessful, NTH
generates an error and the edit
chain is not changed.
Note that (NTH n) is just a special case of (NTH $), and in
fact, no special check is made for $ a number; both commands
are executed identically.
(pattern :: . $)
E.g., (COND :: RETURN). Finds a
COND that contains a RETURN, at any
depth. Equivalent to (F pattern N),
(LCL . $) followed by (← pattern).
For example, if the current expression is (PROG NIL
(COND ((NULL L) (COND (FLG (RETURN L))))) --), then (COND ::
RETURN) will make (COND (FLG (RETURN L))) be the current
expression. Note that it is the innermost COND that is
found, because this is the first COND encountered when
ascending from the RETURN. In other words, (pattern :: $)
is not equivalent to (F pattern N), followed by (LCL . $)
followed by <.
Note that $ is a location specification, not just a
pattern. Thus (RETURN :: COND 2 3) can be used to find the
RETURN which contains a COND whose first clause contains (at
least) three elements. Note also that since $ permits any
edit command, the user can write commands of the form (COND
:: (RETURN :: COND)), which will locate the first COND that
2 . 34
contains a RETURN that contains a COND.
2 . 35
Commands That Save and Restore the Edit Chain
Three facilities are available for saving the current
edit chain and later retrieving it. The commands are MARK,
which marks the current chain for future reference, ←, (An
atomic command; do not confuse with the list command (←
pattern).) which returns to the last mark without destroying
it, and ←←, which returns to the last mark and also erases
it.
MARK
Adds the current edit chain to the
front of the list MARKLIST.
←
Makes the new edit chain be (CAR
MARKLIST). Generates an error if
MARKLIST is NIL, i.e., no MARKS have
been performed, or all have been
erased.
←←
Similar to ← but also erases the
MARK, i.e., performs (SETQ MARKLST
(CDR MARKLST)).
If the user did not prepare in advance for returning to
a particular edit chain, he may still be able to return to
that chain with a single command by using < or <P.
<
Makes the edit chain be the value of
UNFIND. Generates an error if
UNFIND=NIL.
UNFIND is set to the current edit chain by each command
that makes a "big jump", i.e., a command that usually
performs more than a single ascent or descent, namely ↑, ←,
←←, !NX, all commands that involve a search, e.g., F, LC,
::, BELOW, et al and < and <P themselves. (Except that
UNFIND is not reset when the current edit chain is the top
level expression, since this could always be returned to via
the ↑ command.)
For example, if the user types F COND, and then F CAR,
< would take him back to the COND. Another < would take him
back to the CAR, etc.
2 . 36
<P
Restores the edit chain to its state
as of the last print operation,
i.e., P, ?, or PP. If the edit
chain has not changed since the last
printing, <P restores it to its
state as of the printing before that
one, i.e., two chains are always
saved.
For example, if the user types P followed by 3 2 1 P,
<P will return to the first P, i.e., would be equivalent to
0 0 0. (Note that if the user had typed P followed by F
COND, he could use either < or <P to return to the P, i.e.,
the action of < and <P are independent.) another <P would
then take him back to the second P, i.e., the user could use
<P to flip back and forth between the two edit chains.
(S var . $)
Sets var (using SETQ) to the current
expression after performing (LC .
$). Edit chain is not changed.
Thus (S FOO) will set FOO to the current expression, (S
FOO -1 1) will set FOO to the first element in the last
element of the current expression.
2 . 37
Commands That Modify Structure
The basic structure modifications commands in the
editor are:
(n)
n>1 deletes the corresponding
element from the current expression.
(n e1 ... em)
n,m>1 replaces the nth element in
the current expression with e1 ...
em.
(-n e1 ... em)
n,m>1 inserts e1 ... em before the
n element in the current expression.
(N e1 ... em)
m>1 attaches e1 ... em at the end
of the current expression.
As mentioned earlier:
All structure modificaton done by the editor is destructive,
i.e., the editor uses RPLACA and RPLACD to physically
change the structure it was given.
However, all structure modification is undoable, see
UNDO p. 2.76.
All of the above commands generate errors if the
current expression is not a list, or in the case of the
first three commands, if the list contains fewer than n
elements. In addition, the command (1), i.e., delete the
first element, will cause an error if there is only one
element, since deleting the first element must be done by
replacing it with the second element, and then deleting the
second element. Or, to look at it another way, deleting the
first element when there is only one element would require
changing a list to an atom (i.e. to NIL) which cannot be
done. (However, the command DELETE will work even if there
is only one element in the current expression, since it will
ascend to a point where it can do the deletion.)
2 . 38
Implementation of Structure Modification Commands
Note: Since all commands that insert, replace, delete or
attach structure use the same low level editor functions,
the remarks made here are valid for all structure changing
commands.
For all replacement, insertion, and attaching at the
end of a list, unless the command was typed in directly to
the editor, copies of the corresponding structure are used,
because of the possibility that the exact same command,
(i.e. same list structure) might be used again. (Some
editor commands take as arguments a list of edit commands,
e.g. (LP F FOO (1 (CAR FOO))). In this case, the command
(1 (CAR FOO)) is not considered to have been "typed in" even
though the LP command itself may have been typed in.
Similarly, commands originating from macros, or commands
given to the editor as arguments to EDITF, EDITV, et al,
e.g. (EDITF FOO F COND (N --)) are not considered typed
in.) Thus if the program constructs the command (1 (A B C))
via (LIST 1 FOO), and gives this command to the editor, the
(A B C) used for the replacement will NOT be EQ to FOO.
(The user can circumvent this by using the I command, which
computes the structure to be used. In the above example,
the form of the command would be (I 1 FOO), which would
replace the first element with the value of FOO itself. See
p. 2.63)
The rest of this section is included for applications
wherein the editor is used to modify a data structure, and
pointers into that data structure are stored elsewhere. In
these cases, the actual mechanics of structure modification
must be known in order to predict the effect that various
commands may have on these outside pointers. For example,
if the value of FOO is CDR of the current expression, what
will the commands (2), (3), (2 X Y Z), (-2 X Y Z), etc., do
to FOO?
Deletion of the first element in the current expression
is performed by replacing it with the second element and
deleting the second element by patching around it. Deletion
of any other element is done by patching around it, i.e.,
the previous tail is altered. Thus if FOO is EQ to the
current expression which is (A B C D), and FIE is CDR of
FOO, after executing the command (1), FOO will be (B C D)
(which is EQUAL but not EQ to FIE). However, under the same
initial conditions, after executing (2) FIE will be
unchanged, i.e., FIE will still be (B C D) even though the
2 . 39
2.40 current expression and FOO are now (A C D). (A general
solution of the problem just isn't possible, as it would
require being able to make two lists EQ to each other that
were originally different. Thus if FIE is CDR of the
current expression, and FUM is CDDR of the current
expression, performing(2) would have to make FIE be EQ to
FUM if all subsequent operations were to update both FIE and
FUM correctly. Think about it.)
Both replacement and insertion are accomplished by
smashing both CAR and CDR of the corresponding tail. Thus,
if FOO were EQ to the current expression, (A B C D), after
(1 X Y Z), FOO would be (X Y Z B C D). Similarly, if FOO
were EQ to the current expression, (A B C D), then after (-1
X Y Z), FOO would be (X Y Z A B C D).
The N command is accomplished by smashing the last CDR
of the current expression a la NCONC. Thus, if FOO were EQ
to any tail of the current expression, after executing an N
command, the corresponding expressions would also appear at
the end of FOO.
In summary, the only situation in which an edit
operation will not change an external pointer occurs when
the external pointer is to a proper tail of the data
structure, i.e., to CDR of some node in the structure, and
the operation is deletion. If all external pointers are to
elements of the structure, i.e., to CAR of some node, or if
only insertions, replacements, or attachments are performed,
the edit operation will always have the same effect on an
external pointer as it does on the current expression.
2 . 40
The A,B,: Commands
In the (n), (n e1 ... em), and (-n e1 ... em)
commands, the sign of the integer is used to indicate the
operation. As a result, there is no direct way to express
insertion after a particular element, (hence the necessity
for a separate N command). Similarly, the user cannot
specify deletion or replacement of the NTH element from the
end of a list without first converting n to the
corresponding positive integer. Accordingly, we have:
(B e1 ... em)
Inserts e1 ... em before the
current expression. Equivalent to
UP followed by (-1 e1 ... em).
For example, to insert FOO before the last element in
the current expression, perform -1 and then (B FOO).
(A e1 ... em)
Inserts e1 ... em after the current
expression. Equivalent to UP
followed by (-2 e1 ... em) or (N e1
... em) or (N e1 ... em) whichever
is appropriate.
(: e1 ... em)
Replaces the current expression by
e1 ... em. Equivalent to UP
followed by (1 e1 ... em).
DELETE or (:)
Deletes the current expression, or
if the current expression is a tail,
deletes its first element.
DELETE first tries to delete the current expression by
performing an UP and then a (1). This works in most cases.
However, if after performing UP, the new current expression
contains only one element, the command (1) will not work.
Therefore DELETE starts over and performs a BK, followed by
UP, followed by (2). For example, if the current expression
is (COND ((MEMB X Y)) (T Y)), and the user performs -1, and
then DELETE, the BK-UP-(2) method is used, and the new
current expression will be ... ((MEMB X Y)))
However, if the next higher expression contains only
one element, BK will not work. So in this case, DELETE
performs UP, followed by (: NIL), i.e., it REPLACES the
2 . 41
higher expression by NIL. For example, if the current
expression is (COND ((MEMB X Y)) (T Y)) and the user
performs F MEMB and then DELETE, the new current expression
will be ... NIL (T Y)) and the original expression would
now be (COND NIL (T Y)). The rationale behind this is that
deleting (MEMB X Y) from ((MEMB X Y)) changes a list of one
element to a list of no elements, i.e., () or NIL. Note
that 2 followed by DELETE would DELETE ((MEMB X Y)) NOT
replace it by NIL.
If the current expression is a tail, then B, A, and :
will work exactly the same as though the current expression
were the first element in that tail. Thus if the current
expression were ... (PRINT Y) (PRINT Z)), (B (PRINT X))
would insert (PRINT X) before (PRINT Y), leaving the current
expression ...(PRINT X) (PRINT Y) (PRINT Z)).
2 . 42
The following forms of the A, B, and : commands
incorporate a location specification:
(INSERT e1 ... em BEFORE . $)
Similar to (LC. $) followed by (B
e1 ... em).
#P
(PROG (W Y X) (SELECTQ ATM & NIL) (OR & &) (PRIN1 &))
#(INSERT LABEL BEFORE PRIN1)
#P
(PROG (W Y X) (SELECTQ ATM & NIL) (OR & &) LABEL (PRIN1 &))
#
Current edit chain is not changed,
but UNFIND is set to the edit chain
after the B was performed, i.e., <
will make the edit chain be that
chain where the insertion was
performed.
(INSERT e1 ... em AFTER . $)
Similar to INSERT BEFORE except uses
A instead of B.
(INSERT e1 ... em FOR . $)
Similar to INSERT BEFORE except uses
: for B.
(REPLACE $ WITH e1 ... em)
Here $ is the segment of the command
between REPLACE and WITH. Same as
(INSERT e1 ... em FOR . $). (BY
can be used for WITH.)
Example: (REPLACE COND -1 WITH (T (RETURN L)))
(CHANGE $ TO e1 ... em)
Same as REPLACE WITH
(DELETE . $)
Does a (LC . $) followed by
DELETE. Current edit chain is not
changed (Unless the current
expression is no longer a part of
the expression being edited, e.g.,
if the current expression is ... C)
and the user performs (DELETE 1),
2 . 43
the tail, (C), will have been cut
off. Similarly, if the current
expression is (CDR Y) and the user
performs (REPLACE WITH (CAR X)).),
but UNFIND is set to the edit chain
after the DELETE was performed.
Example: (DELETE -1), (DELETE COND 3)
Note that if $ is NIL (empty), the corresponding
operation is performed here (on the current edit chain),
e.g., (REPLACE WITH (CAR X)) is equivalent to (:(CAR X)).
For added readability, HERE is also permitted, e.g., (INSERT
(PRINT X) BEFORE HERE) will insert (PRINT X) before the
current expression (but not change the edit chain).
Note also that $ does not have to specify a location
WITHIN the current expression, i.e., it is perfectly legal
to ascend to INSERT, REPLACE, or DELETE. For example
(INSERT (RETURN) AFTER ↑ PROG -1) will go to the top, find
the first PROG, and insert a (RETURN) at its end, and not
change the current edit chain.
Finally, the A, B, and : commands, (and consequently
INSERT, REPLACE, and CHANGE), all make special checks in E1
thru Em for expressions of the form (## . coms). In this
case, the expression used for inserting or replacing is a
copy of the current expression after executing coms, a list
of edit commands. (The execution of coms does not change
the current edit chain.) For example, (INSERT (## F COND -1
-1) AFTER3) [not (INSERT F COND -1 (## -1 ) AFTER 3), which
inserts four elements after the third element, namely F,
COND, -1, and a copy of the last element in the current
expression] will make a copy of the last form in the last
clause of the next COND, and insert it after the third
element of the current expression.
2 . 44
Form Oriented Editing and the Role of UP
The UP that is performed before A, B, and : commands
(and therefore in INSERT, CHANGE, REPLACE, and DELETE
commands after the location portion of the operation has
been performed.), makes these operations form-oriented. For
example, if the user types F SETQ, and then DELETE, or
simply (DELETE SETQ), he will delete the entire SETQ
expression, whereas (DELETE X) if X is a variable, deletes
just the variable X. In both cases, the operation is
performed on the corresponding FORM and in both cases is
probably what the user intended. Similarly, if the user
types (INSERT (RETURN Y) BEFORE SETQ), he means before the
SETQ expression, not before the atom SETQ. (*There is some
ambiguity in (INSERT expr AFTER functionname), as the user
might mean make expr be the function's first argument.
Similarly, the user cannot write (REPLACE SETQQ WITH SETQ)
meaning change the name of the function. The user must in
these cases write (INSERT expr AFTER functionname 1), and
(REPLACE SETQQ 1 WITH SETQ).) A consequent of this
procedure is that a pattern of the form (SETQ Y --) can be
viewed as simply an elaboration and further refinement of
the pattern SETQ. Thus (INSERT (RETURN Y) BEFORE SETQ) and
(INSERT (RETURN Y) BEFORE (SETQ Y --)) perform the same
operation (Assuming the next SETQ is of the form (SETQ
Y-)).) and, in fact, this is one of the motivations behind
making the current expression after F SETQ, and F (SETQ Y
--) be the same.
Occasionally, however, a user may have a data structure
in which no special significance or meaning is attached to
the position of an atom in a list, as LISP attaches to atoms
that appear as CAR of a list, versus those appearing
elsewhere in a list. In general, the user may not even know
whether a particular atom is at the head of a list or not.
Thus, when he writes (INSERT expression AFTER FOO), he means
after the atom FOO, whether or not it is CAR of a list. By
setting the variable UPFINDFLG to NIL (Initially, and
usually, set to T.) the user can suppress the implicit UP
that follows searches for atoms, and thus achieve the
desired effect. With UPFINDFLG = NIL then following F FOO,
for example, the current expression will be the atom FOO.
In this case, the A, B, and : operations will operate with
respect to the atom FOO. If the user intends the operation
to refer to the list which FOO heads, he simply uses instead
the pattern (FOO --).
2 . 45
Extract and Embed
Extraction involves replacing the current expression with
one of its subexpressions (from any depth).
(XTR . $)
Replaces the original current
expression with the expression that
is current after performing (LCL .
$).
For example, if the current expression is (COND ((NULL X)
(PRINT Y))), (XTR PRINT), or (XTR 2 2) will replace the COND
by the PRINT.
If the current expression after (LCL
. $) is a tail of a higher
expression, its first element is
used.
For example, if the current expression is
(COND ((NULL X) Y) (T Z)), then (XTR Y) will replace the
COND with Y.
If the extracted expression is a
list, then after XTR has finished,
the current expression will be that
list.
Thus, in the first example, the current expression after the
XTR would be (PRINT Y).
If the extracted expression is not a
list, the new current expression
will be a tail whose first element
is that non-list.
Thus, in the second example, the current expression after
the XTR would be ... Y followed by whatever followed by
COND.
If the current expression initially is a tail,
extraction works exactly the same as though the current
expression were the first element in that tail. Thus is the
current expression is (XTR PRINT) will replace the COND by
the PRINT, leaving (PRINT Y) as the current expression.
2 . 46
The extract command can also incorporate a location
specification.
(EXTRACT $1 FROM $2)
($1 is the segment between EXTRACT
and FROM.)
Performs (LC . $2) And then (XTR .
$1). Current edit chain is not
changed, but UNFIND is set to the
edit chain after the XTR was
performed.
Example: If the current expression is
(PRINT (COND ((NULL X) Y) (T Z))) then following
(EXTRACT Y FROM COND), the current expression will be
(PRINT Y).
(EXTRACT 2 -1 FROM COND), (EXTRACT Y FROM 2),
(EXTRACT 2 -1 FROM 2) will all produce the same result.
2 . 47
While extracting replaces the current expression by a
subexpression, embedding replaces the current expression
with one containing it as a subexpression.
(MBD x)
X is a list, substitutes (a la
SUBST, i.e., a fresh copy is used
for each substitution) the current
expression for all instances of the
atom * in x, and replaces the
current expression with the result
of that substitution.
Example: If the current expression is (PRINT Y), (MBD (COND
((NULL X) *) ((NULL (CAR Y)) * (GO LP))) would replace
(PRINT Y) with (COND((NULL X) (PRINT Y)) ((NULL (CAR Y))
(PRINT Y) (GO LP))).
(MBD e1 ... em)
Equivalent to (MBD (e1 ... em *)).
Example: If the current expression is (PRINT Y), then (MBD
SETQ X) will replace it with (SETQ X (PRINT Y)).
(MBD x)
X atomic, same as (MBD (x *)).
Example: If the current expression is (PRINT Y), (MBD
RETURN) will replace it with (RETURN (PRINT Y)).
All three forms of MBD leave the edit chain so that the
larger expression is the new current expression.
If the current expression initially is a tail,
embedding works exactly the same as though the current
expression were the first element in that tail. Thus if the
current expression were (PRINT Y) with (SETQ X (PRINT Y)).
The embed command can also incorporate a location
specification.
2 . 48
(EMBED $ IN . x)
($ is the segment between EMBED and
IN.) Does (LC . $) and then (MBD .
x). Edit chain is not changed, but
UNFIND is set to the edit chain
after the MBD was performed.
Example: (EMBED PRINT IN SETQ X), (EMBED 3 2 IN RETURN),
(EMBED COND 3 1 IN (OR * (NULL X))).
WITH can be used for IN, and SURROUND can be used for EMBED,
e.g., (SURROUND NUMBERP WITH (AND * (MINUSP X ))).
2 . 49
2.50 The MOVE Command
The MOVE command allows the user to specify (1) the
expression to be moved, (2) the place it is to be moved to,
and (3) the operation to be performed there, e.g., insert it
before, insert it after, replace, etc.
(MOVE $1 TO com . $2)
($1 is the segment between MOVE and
TO.) Where COM is BEFORE, AFTER, or
the name of a list command, e.g., :,
N, etc. Performs (LC . $1),
Obtains the current expression there
(or its first element, if it is a
tail), let us call this expr; MOVE
then goes back to original edit
chain, performs (LC . $2), Peforms
(com expr), then goes back to $1 and
deletes expr. Edit chain is not
changed. UNFIND is set to edit
chain after (com expr) was
performed.
For example, if the current expression is (A B D C), (
MOVE 2 TO AFTER 4) will make the new current expression be
(A C D B). Note that 4 was executed as of the original edit
chain, and that the second element had not yet been removed.
2 . 50
As the following examples taken from actual editing
will show, the MOVE command is an extremely versatile and
powerful feature of the editor.
#?
(PROG (L) (EDLOC (CDDR C)) (RETURN (CAR L)))
#(MOVE 3 TO : CAR)
#?
(PROG (L) (RETURN (EDLOC (CDDR C))))
#
#P
... (SELECTQ OBJPR & &) (RETURN &) LP2 (COND & & ))
#(MOVE 2 TO N 1)
#P
... (SELECTQ OBJPR & & &) LP2 (COND & &))
#
#P
(OR (EQ X LASTAIL) (NOT &) (AND & & &))
#(MOVE 4 TO AFTER (BELOW COND))
#P
(OR (EQ X LASTAIL) (NOT &))
#< P
... (& &) (AND & & &) (T & &))
#
#P
((NULL X) (COND & &))
#(-3 (GO DELETE))
#(MOVE 4 TO N (← PROG))
#P
((NULL X) (GO DELETE))
#< P
(PROG (&) (COND & & &) (COND & & &) (COND & &))
#(INSERT DELETE BEFORE -1)
#P
(PROG (&) (COND & & &) (COND & & &) DELETE (COND & &))
#
Note that in the last example, the user could have
added the prog label DELETE and moved the COND in one
operation by performing (MOVE 4 TO N (← PROG) (N DELETE)).
2 . 51
Similarly, in the next example, in the course of specifying
$2, the location where the expression was to be moved to,
the user also performs a structure modification, via (N
(T)), thus creating the structure that will receive the
expression being moved.
#P
((CDR &) (SETQ CL &) (EDITSMASH CL & &))
#(MOVE 4 TO N 0 (N (T)) - 1]
#P
((CDR &) (SETQ CL &))
#< P
(T (EDITSMASH CL & &))
#
If $2 is NIL, or (HERE), the current position specifies
where the operation is to take place. In this case, UNFIND
is set to where the expression that was moved was originally
located, i.e., $1. For example:
#P
(TENEX)
#(MOVE ↑ F APPLY TO N HERE)
#P
(TENEX (APPLY & & ))
#
#P
(T (PRIN1 C-EXP))
#(MOVE BF PRIN1 TO N HERE)
#P
(T (PRIN1 C-EXP) (PRIN1 &))
#
Finally, if $1 is NIL, the MOVE command allows the user
to specify some place the current expression is to be moved
to. In this case, the edit chain is changed, and is the
chain where the current expression was moved to; UNFIND is
set to where it was.
#P
(SELECTQ OBJPR (&) (PROGN & &))
2 . 52
#(MOVE TO BEFORE LOOP)
#P
...(SELECTQ OBJPR & &) LOOP (RPLACA DFPRP &) (RPLACD DFPRP &))
#
2 . 53
Commands That "Move Parentheses"
The commands presented in this section permit
modification of the list structure itself, as opposed to
modifying components thereof. Their effect can be described
as inserting or removing a single left or right parenthesis,
or pair of left and right parentheses. Of course, there
will always be the same number of left parentheses as right
parentheses in any list structure, since the parentheses are
just a notational guide to the structure provided by PRINT.
Thus, no command can insert or remove just one parenthesis,
but this is suggestive of what actually happens.
In all six commands, n and m are used to specify an
element of a list, usually of the current expression. In
practice, n and m are usually positive or negative integers
with the obvious interpretation. However, all six commands
use the generalized NTH command, p. 2.34, To find their
element(s), so that nth element means the first element of
the tail found by performing (NTH n). In other words, if
the current expression is (LIST (CAR X) (SETQ Y (CONS W
Z))), then (BI 2 CONS), (BI X -1), and (BI X Z) all specify
the exact same operation.
All six commands generate an error if the element is
not found, i.e., the NTH fails. All are undoable.
(BI n m)
Both in, inserts a left parentheses
before the nth element and after the
mth element in the current
expression. Generates an error if
the mth element is not contained in
the nth tail, i.e., the mth element
must be "to the right" of the nth
element.
Example: If the current expression is (A B (C D E) F G),
then (BI 2 4) will modify it to be (A (B (C D E) F) G).
(BI n)
Same as (BI n n).
Example: If the current expression is (A B (C D E) F G),
then (BI -2) will modify it to be (A B (C D E) (F) G).
2 . 54
(BO n)
Both out. Removes both parentheses
from the nth element. Generates an
error if nth element is not a list.
Example: If the current expression is (A B (C D E) F G),
then (BO D) will modify it to be (A B C D E F G).
(LI n)
Left in, inserts a left parenthesis
before the nth element (and a
matching right parenthesis at the
end of the current expression),
i.e., equivalent to (BI n -1).
Example: If the current expression is (A B (C D E) F G),
then (LI 2) will modify it to be (A (B (C D E) F G)).
(LO n)
Left out, removes a left parenthesis
from the nth element. All elements
following the nth element are
deleted. Generates an error if nth
element is not a list.
Example: If the current expression is (A B (C D E) F G),
then (LO 3) will modify it to be (A B C D E).
(RI n m)
Right in, inserts a right
parenthesis after the mth element of
the nth element. The rest of the
nth element is brought up to the
level of the current expression.
Example: If the current expression is (A (B C D E) F G), (RI
2 2) will modify it to be (A (B C) D E F G). Another way of
thinking about RI is to read it as "move the right
parenthesis at the end of the nth element IN to after the
mth element."
2 . 55
(RO n)
Right out, removes the right
parenthesis from the nth element,
moving it to the end of the current
expression. All elements following
the nth element are moved inside of
the nth element. Generates an error
if nth element is not a list.
Example: If the current expression is (A B (C D E) F G), (RO
3) will modify it to be (A B (C D E F G)). Another way of
thinking about RO is to read it as "move the right
parenthesis at the end of the nth element OUT to the end of
the current expression."
2 . 56
TO and THRU
EXTRACT, EMBED, DELETE, REPLACE, and MOVE can be made
to operate on several contiguous elements, i.e., a segment
of a list, by using the TO or THRU command in their
respective location specifications.
($1 THRU $2)
Does a (LC . $1), Followed by an
UP, and then a (BI 1 $2), thereby
grouping the segment into a single
element, and finally does a 1,
making the final current expression
be that element.
For example, if the current expression is (A (B (C D) (E) (F
G H) I) J K), following (C THRU G), the current expression
will be ((C D) (E) (F G H)).
($1 TO $2)
Same as THRU except last element not
included, i.e., after the BI, an (RI
1 -2) is performed.
If both $1 and $2 are numbers, and $2 is greater than
$1, then $2 counts from the beginning of the current
expression, the same as $1. In other words, if the current
expression is (A B C D E F G), (3 THRU 4) means (C THRU D),
not (C THRU F). In this case, the corresponding BI command
is (BI 1 $2-$1+1).
THRU and TO are not very useful commands by themselves,
and are not intended to be used "solo", but in conjunction
with EXTRACT, EMBED, DELETE, REPLACE, and MOVE. After THRU
and TO have operated, they set an internal editor flag
informing the above commands that the element they are
operating on is actually a segment, and that the extra pair
of parentheses should be removed when the operation is
complete. Thus:
#P
(PROG NIL (SETQ A &) (RPLACA & &) (PRINT &) (RPLACD & &))
#(MOVE (3 THRU 4) TO BEFORE 5) P
(PROG NIL (PRINT &) (SETQ A &) (RPLACA & &) (RPLACD & &))
#
Note that when specifing $2 in the MOVE, 5 was used instead
2 . 57
of 6. This is because the $2 is located after $1 is. The
THRU location groups items together and thus changes the
numeric location of the following items.
#P
(PROG NIL (PRIN1 &) (PRIN1 &) (SETQ IND &) (SETQ VAL &) (PRINT &))
#(MOVE (5 THRU 7) TO BEFORE 3)
#P
(PROG NIL (SETQ IND &) (SETQ VAL &) (PRINT &) (PRIN1 &) (PRIN1 &))
#(DELETE (SETQ THRU PRI@))
= PRINT
#P
(PROG NIL (PRIN1 &) (PRIN1 &))
#
#P
... LP (SELECTQ & & &) (SETQ Y &) OUT (SETQ FLG &) (RETURN Y))
#(MOVE (1 TO OUT) TO N HERE)
#P
... OUT (SETQ FLG &) (RETURN Y) LP (SELECTQ & & &) (SETQ Y &))
#
#PP
(PROG (TEMP1 TEMP2)
(COND ((NOT (MEMQ REMARG LISTING))
(SETQ TEMP1 (ASSOC REMARG NAMEDREMARKS))
(SETQ TEMP2 (CADR TEMP1)))
(T (SETQ TEMP1 REMARG)))
(NCONC LISTING REMARG)
(RETURN (CONS TEMP1 TEMP2)))
#(EXTRACT (SETQ THRU CADR) FROM COND) PP
(PROG (TEMP1 TEMP2)
(SETQ TEMP1 (ASSOC REMARG NAMEDREMARKS))
(SETQ TEMP2 (CADR TEMP1))
(NCONS LISTING REMARG)
(RETURN (CONS TEMP1 TEMP2)))
#
TO and THRU can also be used directly with XTR.
(Because XTR involves a location specification while A,B,:,
and MBD do not.) Thus in the previous example, if the
current expression had been the COND, e.g., the user had
first performed F COND , he could have used (XTR (SETQ THRU
CADR)) to perform the extraction.
2 . 58
($1 TO), ($1 THRU)
Both same as ($1 THRU -1), i.e.,
from $1 thru the end of the list.
#P
(VAL (RPLACA DFPRP &) (RPLACD & &) (RPLACA VARS &) (RETURN &))
#(MOVE (2 TO) TO N (← PROG))
#(N (GO VAR))
#P
(VAL (GO VAR))
#
#P
(T (COND &) (EDITSMASH CL & &) (COND &))
#(-2 (GO REPLACE))
#(MOVE (COND TO) TO N PROG (N REPLACE))
#P
(T (GO REPLACE))
#< P
(PROG (&) (COND & & &) (COND & & &) DELETE (COND & &) REPLACE
(COND &) (EDITSMASH CL & &) (COND &))
#
#PP
(LAMBDA(CLAUSALA X)
(PROG (A D)
(SETQ A CLAUSALA)
LP (COND ((NULL A) (RETURN NIL)))
(SERCH X A)
(RUMARK (CAR A))
(NOTICECL (CAR A))
(SETQ A (CDR A))
(GO LP)))
#(EXTRACT (SERCH THRU NOT@) FROM PROG) P
= NOTICECL
(LAMBDA (CLAUSALA X) (SERCH X A) (RUMARK &) (NOTICECL &))
#(EMBED (SERCH TO) IN (MAP [FUNCTION (LAMBDA (A) *] CLAUSALA]
#PP
(LAMBDA(CLAUSALA X)
(MAP (FUNCTION
(LAMBDA(A)
(SERCH X A)
(RUMARK (CAR A))
(NOTICECL (CAR A))))
CLAUSALA))
2 . 59
2.60 (R x y)
Replaces all instances of x by y in
the current expression, e.g., (R
CAADR CADAR). Generates an error if
there is not at least one instance.
R operates by performing a DSUBST. The current
expression is the third argument to DSUBST, i.e., the
expression being substituted into, and y is the first
argument to DSUBST, i.e., the expression being substituted.
R computes the second argument to DSUBST, the expression to
be substituted for, by performing (F x T). The second
argument is then the current expression at that point, or if
that current expression is a list and x is atomic, then the
first element of that current expression. Thus x can be the
S-expression (or atom) to be substituted for, or can be a
pattern which specifies that S-expression (or atom).
For example, if the current expression is (LIST FUNNYATOM1
FUNNYATOM2 (CAR FUNNYATOM1)), then (R FUN@ FUNNYATOM3 ) will
substitute FUNNYATOM3 for FUNNYATOM1 throughout the current
expression. Note that FUNNYATOM2, even though it would have
matched with the pattern FUN@, is NOT replaced.
Similarly, if (LIST(CAR X) (CAR Y)) is the first
expression matched by (LIST --), then (R (LIST --) (LIST
(CAR Y) (CAR Z))) is equivalent to (R (LIST (CARX) (CARY))
(LIST (CAR Y) (CAR Z))), i.e., both will replace all
instances of (LIST (CAR X) (CAR Y)) by (LIST (CAR Y) (CAR
Z)). Note that other forms beginning with LIST will not be
replaced, even though they would have matched with (LIST
--). To change all expressions of the form (LIST --) to
(LIST (CAR Y) (CAR Z)), the user should perform (LP (REPLACE
(LIST --) WITH (LIST (CAR Y) (CAR].
UNFIND is set to the edit chain following the find command
so that < will make the current expression be the place
where the first substitution occurred.
2 . 60
(SW n m)
Switches the nth and mth elements of
the current expression.
For example, if the current expression is (LIST (CONS (CAR
X) (CAR Y)) (CONS (CDR Y))), (SW 2 3) will modify it to be
(LIST (CONS (CDR X) (CDR Y)) (CONS (CAR X) (CAR Y))). The
relative order of n and m is not important, ie, (SW 3 2)
and (SW 2 3 ) are equivalent.
SW uses the generalized NTH command
to find the nth and mth elements, a
la the BI-BO commands.
Thus in the previous example, (SW CAR CDR) would produce the
same result.
2 . 61
Commands That Print
P
Prints current expression as though
PRINTLEV were given a depth of 2.
(P m)
Prints mth element of current
expression as though PRINTLEV were
given a depth of 2.
(P 0)
Same as P
(P m n)
Prints mth element of current
expression as though PRINTLEV were
given a depth of N.
(P 0 n)
Prints current expression as though
PRINTLEVEL were given a depth of N.
?
Same as (P 0 100)
Both (P m) and (P m n) use the general NTH command to
obtain the corresponding element, so that m does not have to
be a number, e.g. (P COND 3) will work.
All printing functions print to the teletype,
regardless of the primary output file. No printing function
ever changes the edit chain. All record the current edit
chain for use by <P, p. 2.37.
2 . 62
Commands That Evaluate
E
Only when typed in, (i.e., (INSERT D
BEFORE E) will treat E as a pattern)
causes the editor to call the LISP
interpreter giving it the next input
as argument.
Example:
#E (BREAK FIE FUM)
(FIE FUM)
#E (FOO)
(FIE BROKEN)
1:
(E x)
Evaluates X, i.e., performs (EVAL
x), and prints the result on the
teletype.
(E x T)
Same as (E x) but does not print.
The (E x) and (E x T) commands are mainly intended for
use by MACROS and subroutine calls to the editor; the user
would probably type in a form for evaluation using the more
convenient format of the (atomic) E command.
(I c x1 ... xn)
Same as (c y1 ... yn) where
yi=(EVAL xi).
Example: (I 3 (GETD (QUOTE FOO)) will replace the 3rd
element of the current expression with the definition of
FOO. (The I command sets an internal flag to indicate to
the structure modification commands not to copy
expression(s) when inserting, replacing, or attaching.) (I N
FOO (CAR FIE)) will attach the value of FOO and CAR of the
value of FIE to the end of the current expression. (I F=
FOO T) will search for an expression EQ to the value of FOO.
If c is not an atom, it is evaluated
as well.
Example: (I (COND ((NULL FLG) (QUOTE -1)) (T 1)) FOO), if
FLG is NIL, inserts the value of FOO before the first
element of the current expression, otherwise replaces the
2 . 63
first element by the value of FOO.
(## com[1] com[2] ... com[n])
is an FSUBR (not a command). Its
value is what the current expression
would be after executing the edit
commands com[1] ... com[n] starting
from the present edit chain.
Generates an error if any of com[1]
thru com[n] cause errors. The
current edit chain is never changed.
(Recall that A,B,:,INSERT, REPLACE,
and CHANGE make special checks for
## forms in the expressions used for
inserting or replacing, and use a
copy of ## form instead (see p.
2.44). thus, (INSERT (## 3 2) AFTER
1) is equivalent to (I INSERT (COPY
(## 3 2 )) (QUOTE AFTER) 1).)
Example: (I R (QUOTE X) (## (CONS ..Z))) replaces all X's in
the current expression by the first CONS containing a Z.
The I command is not very convenient for computing an
entire edit command for execution, since it computes the
command name and its arguments separately. Also, the I
command cannot be used to compute an atomic command. The
following two commands provide more general ways of
computing commands.
(COMS x1 ... xn)
Each xi is evaluated and its value
executed as a command.
For example, (COMS (COND (X (LIST 1 X)))) will replace the
first element of the current expression with the value of X
if non-NIL, otherwise do nothing. (NIL as a command is a
NOP, see p. 2.71.)
(COMSQ com[1] ... com[n])
Executes com[1] ... com[n].
COMSQ is mainly useful in conjunction with the COMS command.
For example, suppose the user wishes to compute an entire
list of commands for evaluation, as opposed to computing
each command one at a time as does the COMS command. He
would then write (COMS (CONS (QUOTE COMSQ) x)) where x
computed the list of commands, e.g.,
2 . 64
(COMS (CONS (QUOTE COMSQ) (GET FOO (QUOTE COMMANDS)))).
2 . 65
Commands That Test
(IF x)
Generates an error unless the value
of (EVAL x) is true, i.e., if (EVAL
x) causes an error or (EVAL x)=NIL,
IF will cause an error.
For some editor commands, the occurrence of an error
has a well defined meaning, i.e., they use errors to branch
on as COND uses NIL and non-NIL. For example, an error
condition in a location specification may simply mean "not
this one, try the next." Thus the location specification
(*PLUS (E (OR (NUMBERP (## 3)) (ERR NIL)) T))
specifies the first *PLUS whose second argument is a number.
The IF command, by equating NIL to error, provides a more
natural way of accomplishing the same result. Thus, an
equivalent location specification is (*PLUS (IF (NUMBERP (##
3)))).
The IF command can also be used to select between two
alternate lists of commands for execution.
(IF x coms1 coms2)
If (EVAL x) is true, execute coms1;
if (EVAL x) causes an error or is
equal to NIL, execute coms2.
For example, the command (IF (NULL A) NIL (P)) will print
the current expression provided A=NIL.
(IF x coms1)
If (EVAL x) is true, execute coms1;
otherwise generate an error.
(LP . coms)
Repeatedly executes coms, a list of
commands, until an error occurs.
For example, (LP F PRINT (N T)) will attach a T at the
end of every PRINT expression. (LP F PRINT (IF (## 3) NIL
((N T)))) will attach a T at the end of each print
expression which does not already have a second argument.
(i.e. The form (## 3) will cause an error if the edit
command 3 causes an error, thereby selecting ((N T)) as the
list of commands to be executed. The IF could also be
written as (IF (CDDR (##)) NIL ((N T))).)
2 . 66
When an error occurs, LP prints n
OCCURRENCES, where n is the number
of times COMS was successfully
executed. The edit chain is left as
of the last complete successful
execution of COMS.
(LPQ . Coms)
Same as LP but does not print n
OCCURRENCES.
In order to prevent non-terminating loops, both LP and
LPQ terminate when the number of iterations reaches MAXLOOP,
initially set to 30.
(ORR coms[1] ... Coms[n])
ORR begins by executing coms[1], a
list of commands. If no error
occurs, ORR is finished. Otherwise,
ORR restores the edit chain to its
original value, and continues by
executing coms[2], etc. If none of
the command lists execute without
errors, i.e., the ORR "drops off the
end", ORR generates an error.
Otherwise, the edit chain is left as
of the completion of the first
command list which executes without
error. (NIL as a command list is
perfectly legal, and will always
execute successfully. Thus, making
the last 'argument' to ORR be NIL
will insure that the ORR never
causes an error. Any other atom is
treated as (atom), i.e., the example
given below could be written as (ORR
NX !NX NIL).)
For example, (ORR (NX) (!NX) NIL) will perform a NX, if
possible, otherwise a !NX, if possible, otherwise do
nothing. Similarly, DELETE could be written as (ORR (UP
(1)) (BK UP (2)) (UP (: NIL))).
2 . 67
Macros
Many of the more sophisticated branching commands in
the editor, such as ORR, IF, etc., are most often used in
conjunction with edit macros. The macro feature permits the
user to define new commands and thereby expand the editor's
repertoire. (However, built in commands always take
precedence over macros, i.e., the editor's repertoire can be
expanded, but not modified.) Macros are defined by using the
M command.
(M c . coms)
For c an atom, M defines c as an
atomic command. (If a macro is
redefined, its new definition
replaces its old.) Executing c is
then the same as executing the list
of commands COMS.
For example, (M BP BK UP P) will define BP as an atomic
command which does three things, a BK, an UP, and a P. Note
that macros can use commands defined by macros as well as
built in commands in their definitions. For example,
suppose Z is defined by (M Z -1 (IF (NULL (##)) NIL (P))),
i.e. Z does a -1, and then if the current expression is not
NIL, a P. Now we can define ZZ by (M ZZ -1 Z), and ZZZ by
(M ZZZ -1 -1 Z) or (M ZZZ -1 ZZ).
Macros can also define list commands, i.e., commands
that take arguments.
(M (c) (arg[1] ... arg[n]) . coms)
C an atom. M defines c as a list
command. Executing (c e1 ... en)
is then performed by substituting e1
for arg[1], ... en for arg[n]
throughout COMS, and then executing
COMS.
For example, we could define a more general BP by (M
(BP) (N) (BK N) UP P). Thus, (BP 3) would perform (BK 3),
followed by an UP, followed by a P.
A list command can be defined via a macro so as to take
a fixed or indefinite number of 'arguments'. The form given
above specified a macro with a fixed number of arguments, as
indicated by its argument list. If the 'argument list' is
atomic, the command takes an indefinite number of arguments.
2 . 68
(M (c) args . coms)
Name, args both atoms, defines c as
a list command. executing (c e1 ...
en) is performed by substituting (e1
... en), i.e., CDR of the command,
for args throughout coms, and then
executing coms.
For example, the command SECOND, p. 2.31, can be
defined as a macro by (M (2ND) X (ORR ((LC . X) (LC .
X)))). Note that for all editor commands, 'built in'
commands as well as commands defined by macros, atomic
definitions and list definitions are completely independent.
In other words, the existence of an atomic definition for c
in no way affects the treatment of c when it appears as CAR
of a list command, and the existence of a list definition
for c in no way affects the treatment of c when it appears
as an atom. in particular, c can be used as the name of
either an atomic command, or a list command, or both. In
the latter case, two entirely different definitions can be
used.
Note also that once c is defined as an atomic command
via a macro definition, it will not be searched for when
used in a location specification, unless c is preceded by an
F. Thus (INSERT -- BEFORE BP) would not search for BP, but
instead perform a BK, an UP, and a P, and then do the
insertion. The corresponding also holds true for list
commands.
Occasionally, the user will want to employ the S
command in a macro to save some temporary result. For
example, the SW command could be defined as
(M (SW) (N M) (NTH N) (S FOO 1) MARK 0 (NTH M) (S FIE 1) (I
1 FOO) ←← (I 1 FIE))
(A more elegant definition would be (M (SW) (N M) (NTH N)
MARK 0 (NTH M) (S FIE 1) (I 1 (## ← 1)) ←← (I 1 FIE)), but
this would still use one free variable.)
Since SW sets FOO and FIE, using SW may have
undesirable side effects, especially when the editor was
called from deep in a computation. Thus we must always be
careful to make up unique names for dummy variables used in
edit macros, which is bothersome. Furthermore, it would be
impossible to define a command that called itself
recursively while setting free variables. The BIND command
2 . 69
2.70 solves both problems.
(BIND . coms)
Binds three dummy variables #1, #2,
#3, (initialized to NIL), and then
executes the edit commands COMS.
Note that these bindings are only in
effect while the commands are being
executed, and that BIND can be used
recursively; it will rebind #1, #2,
and #3 each time it is invoked.
(BIND is implemented by (PROG (#1 #2
#3) (EDITCOMS (CDR COM))) where COM
corresponds to the BIND command, and
EDITCOMS is an internal editor
function which executes a list of
commands.)
thus we could now write SW safely as
(M (SW) (N M) (BIND (NTH N) (S #1 1) MARK 0 (NTH M) (S #2 1)
(I 1 #1) ←← (I 1 #2))).
User macros are stored on a list USERMACROS.
(USERMACROS is initially NIL.) thus if the user wants to
save his macros, he should save the value of USERMACROS.
(The user probably should also save the value of EDITCOMSL).
2 . 70
Miscellaneous Commands
NIL
Unless preceded by F or BF, is
always a NOP.
TTY:
Calls the editor recursively. The
user can then type in commands, and
have them executed. The TTY:
command is completed when the user
exits from the lower editor. (See
OK and STOP below.)
The TTY: command is extremely useful. It enables the
user to set up a complex operation, and perform interactive
attention-changing commands part way through it. For
example the command (MOVE 3 TO AFTER COND 3 P TTY:) allows
the user to interact, in effect, within the MOVE command.
Thus he can verify for himself that the correct location has
been found, or complete the specification "by hand". In
effect, TTY: says "I'll tell you what you should do when you
get there."
The TTY: command operates by printing TTY: and then
calling the editor. The initial edit chain in the lower
editor is the one that existed in the higher editor at the
time the TTY: command was entered. Until the user exits
from the lower editor, any attention changing commands he
executes only affect the lower editor's edit chain. (Of
course, if the user performs any structure modification
commands while under a TTY: command, these will modify the
structure in both editors, since it is the same structure.)
When the TTY: command finishes, the lower editor's edit
chain becomes the edit chain of the higher editor.
OK
Exits from the editor.
2 . 71
STOP
Exits from the editor with an error.
Mainly for use in conjunction with
TTY: commands that the user wants to
abort.
Since all of the commands in the editor are ERRSET
protected, the user must exit from the editor via a command.
STOP provides a way of distinguishing between a successful
and unsuccessful (from the user's standpoint) editing
session. For example, if the user is executing (MOVE 3 TO
AFTER COND TTY:), and he exits from the lower editor with an
OK, the MOVE command will then complete its operation. If
the user wants to abort the MOVE command, he must make the
TTY: command generate an error. He does this by exiting
from the lower editor with a STOP command. In this case,
the higher editor's edit chain will not be changed by the
TTY: command.
SAVE
Exits from the editor and saves the
'state of the edit' on the property
list of the function/variable being
edited under the property EDIT-SAVE.
If the editor is called again on the
same structure, the editing is
effectively "continued," i.e., the
edit chain, mark list, value of
UNFIND and UNDOLST are restored.
For example:
#P
(NULL X)
#F COND P
(COND (& &) (T &))
#SAVE
FOO
.
.
.
*(EDITF FOO)
EDIT
#P
(COND (& &) (T &))
#< P
(NULL X)
#
2 . 72
SAVE is necessary only if the user is editing many
different expressions; an exit from the editor via OK always
saves the state of the edit of that call to the editor. (On
the property list of the atom EDIT, under the property name
LASTVALUE. OK also remprops EDIT-SAVE from the property
list of the function/variable being edited.) Whenever the
editor is entered, it checks to see if it is editing the
same expression as the last one edited. In this case, it
restores the mark list, the undolst, and sets UNFIND to be
the edit chain as of the previous exit from the editor. For
example:
*(EDITF FOO)
EDIT
#P
(LAMBDA (X) (PROG & & LP & & & &))
.
.
.
#P
(COND & &)
#OK
FOO
#
.
. Any number of inputs except for
. calls to the editor.
*(EDITF FOO)
EDIT
#P
(LAMBDA (X) (PROG & & LP & & & &))
#< P
(COND & &)
#
The user can always continue editing, including undoing
changes from a previous editing session, if
(1) No other expressions have been edited since
that session; (since saving takes place at exit
time, intervening calls that were exited via STOP
will not affect the editor's memory of this last
session.) or
(2) It was ended with a SAVE command.
2 . 73
REPACK
Permits the 'editing' of an atom or
string.
For example:
#P
... "THIS IS A LOGN STRING")
#REPACK
EDIT
1#P
(/" T H I S / I S / A / L O G N / S T R I N G /")
1#(SW G N)
1#OK
"THIS IS A LONG STRING"
#
REPACK operates by calling the editor recursively on
UNPACK of the current expression, or if it is a list, on
UNPACK of its first element. If the lower editor is exited
successfully, i.e. via OK as opposed to STOP, the list of
atoms is made into a single atom or string, which replaces
the atom or string being 'repacked.' The new atom or string
is always printed.
(REPACK $)
Does (LC . $) followed by REPACK,
e.g. (REPACK THIS@).
2 . 74
2.75 (MAKEFN form args n m)
Makes (CAR form) an EXPR with the
nth through mth elements of the
current expression with each
occurance of an element of (CDR
form) replaced by the corresponding
element of args. The nth through
mth elements are replaced by form.
For example:
#P
... (SETQ A NIL) (SETQ B T) (CONS C D))
#(MAKEFN (SETUP C D) (W X) 1 3) P
... (SETUP C D))
#E (GRINDEF SETUP)
(DEFPROP SETUP
(LAMBDA(W X) (SETQ A NIL) (SETQ B T) (CONS W X))
EXPR)
#
(MAKEFN form args n)
Same as (MAKEFN form args n n).
2 . 75
UNDO
Each command that causes structure modification
automatically adds an entry to the front of UNDOLST
containing the information required to restore all pointers
that were changed by the command.
UNDO
Undoes the last, i.e., most recent,
structure modification command that
has not yet been undone, (Since UNDO
and !UNDO causes structure
modification, they also add an entry
to UNDOLST. However, UNDO and !UNDO
entries are skipped by UNDO, e.g.,
if the user performs an INSERT, and
then an MBD, the first UNDO will
undo the MBD, and the second will
undo the INSERT. However, the user
can also specify precisely which
command he wants undone. In this
case, he can undo an UNDO command,
e.g., by typing UNDO UNDO, or undo a
!UNDO command, or undo a command
other than that most recently ←
performed.) and prints the name of
that command, e.g., MBD UNDONE. The
edit chain is then exactly what it
was before the 'undone' command had
been performed. If there are no
commands to undo, UNDO types NOTHING
SAVED.
!UNDO
Undoes all modifications performed
during this editing session, i.e.,
this call to the editor. As each
command is undone, its name is
printed a la UNDO. If there is
nothing to be undone, !UNDO prints
NOTHING SAVED.
Whenever the user continues an editing session as
described on pages 2.72-2.73, the undo information of the
previous session(s) is protected by inserting a special
blip, called an undo-block on the front of UNDOLST. This
undo-block will terminate the operation of a !UNDO, thereby
confining its effect to the current session, and will
2 . 76
similarly prevent an UNDO command from operating on commands
executed in the previous session.
Thus, if the user enters the editor continuing a
session, and immediately executes an UNDO or !UNDO, UNDO and
!UNDO will type BLOCKED, instead of NOTHING SAVED.
Similarly, if the user executes several commands and then
undoes them all, either via several UNDO commands or a !UNDO
command, another UNDO or !UNDO will also type BLOCKED.
UNBLOCK
Removes an undo-block. If executed
at a non-blocked state, i.e., if
UNDO or !UNDO could operate, types
NOT BLOCKED.
TEST
Adds an undo-block at the front of
UNDOLST.
Note that TEST together with !UNDO provide a
'tentative' mode for editing, i.e., the user can perform a
number of changes, and then undo all of them with a single
!UNDO command.
??
Prints the entries on UNDOLST. The
entries are listed in the reverse
order of their execution, i.e., the
most recent entry first. For
example:
#P
(CONS (T &) (& &))
#(1 COND) (SW 2 3) P
(COND (& &) (T &))
#??
SW (1 --)
#
2 . 77
Editdefault
Whenever a command is not recognized, i.e., is not
'built in' or defined as a macro, the editor calls an
internal function, EDITDEFAULT to determine what action to
take. If a location specification is being executed, an
internal flag informs EDITDEFAULT to treat the command as
though it had been preceded by an F.
If the command is atomic and typed in directly, the
procedure followed is as given below.
1)
If the command is one of the list commands, i.e.,
a member of EDITCOMSL, and there is additional input on
the same teletype line, treat the entire line as a
single list command. (Uses READLINE. Thus the line
can be terminated by carriage return, right parenthesis
or square bracket, or a list.) Thus, the user may omit
parentheses for any list command typed in at the top
level (which is not also an atomic command, e.g., NX,
BK). For example:
#P
(COND (& &) (T &))
#(XTR 3 2)
#MOVE TO AFTER LP
#
If the command is on the list EDITCOMSL but no
additional input is on the teletype line, an error is
generated, e.g.,
#P
(COND (& &) (T &))
#MOVE
MOVE ?
#
2)
If the last character in the command is P, and the
first n-1 characters comprise the command ←←, ←, UP,
NX, BK, !NX, UNDO, or REDO, assume that the user
intended two commands, e.g.,
2 . 78
#P
(COND (& &) (T &))
#2 NXP
(T (CONS X Y))
3)
Otherwise, generate an error.
2 . 79
2.80 Editor Functions
(EDITL L coms atm marklst mess)
EDITL is the editor. Its first
argument is the edit chain, and its
value is an edit chain, namely the
value of L at the time EDITL is
exited. (L is a special variable,
and so can be examined or set by
edit commands. For example, ↑ is
equivalent to (E (SETQ L(LAST L))
T).)
Coms is an optional list of
commands. For interactive editing,
coms is NIL. In this case, EDITL
types EDIT and then waits for input
from the teletype. (If mess is not
NIL EDITL types it instead of EDIT.
For example, the TTY: command is
essentially (SETQ L (EDITL L NIL NIL
NIL (QUOTE TTY:))).) Exit occurs
only via an OK, STOP, or SAVE
command.
If coms is NOT NIL, no message is
typed, and each member of coms is
treated as a command and executed.
If an error occurs in the execution
of one of the commands, no error
message is printed , the rest of the
commands are ignored, and EDITL
exits with an error, i.e., the
effect is the same as though a STOP
command had been executed. If all
commands execute successfully, EDITL
returns the current value of L.
Marklst is the list of marks.
On calls from EDITF, Atm is the name
of the function being edited; on
calls from EDITV, the name of the
variable, and calls from EDITP, the
atom of which some property of its
property list is being edited. The
property list of atm is used by the
SAVE command for saving the state of
2 . 80
the edit. Thus SAVE will not save
anything if atm=NIL i.e., when
editing arbitrary expressions via
EDITE or EDITL directly.
(EDITF x)
FSUBR function for editing a
function. (CAR x) is the name of
the function, (CDR x) an optional
list of commands. For the rest of
the discussion, fn is (CAR x), and
coms is (CDR x).
If x is NIL, fn is set to the value
of LASTWORD, coms is set to NIL, and
the value of LASTWORD is printed.
The value of EDITF is fn.
(1) In the most common case, fn is an non-compiled
function, and EDITF simply performs
(EDITE (CADR (GETL fn (QUOTE (FEXPR EXPR MACRO)))) coms fn)
and sets LASTWORD to fn.
(2) If fn is not an editable function, but has a value,
EDITF assumes the user meant to call EDITV, prints =EDITV,
calls EDITV and returns.
Otherwise, EDITF generates an fn NOT EDITABLE error.
(EDITE expr coms atm)
Edits an expression. Its value is
the last element of (EDITL (LIST
expr) coms atm NIL NIL). Generates
an error if expr is not a list.
2 . 81
(EDITV editvx)
FSUBR function, similar to EDITF,
for editing values. (CAR editvx)
specifies the value, (CDR editvx) is
an optional list of commands.
If editvx is NIL, it is set to the
value of (NCONS LASTWORD) and the
value of LASTWORD is printed.
If (CAR editvx) is a list, it is evaluated and its
value given to EDITE, e.g. (EDITV (CDR (ASSOC (QUOTE FOO)
DICTIONARY)))). In this case, the value of EDITV is T.
However, in most cases, (CAR editvx) is a variable,
e.g. (EDITV FOO); and EDITV calls EDITE on the value of the
variable.
If the value of (CAR editvx) is atomic then EDITV
prints a NOT EDITABLE error message.
When (if) EDITE returns, EDITV sets the variable to the
value returned, and sets LASTWORD to the name of the
variable.
The value of EDITV is the name of the variable whose
value was edited.
(EDITP x)
FSUBR function, similar to EDITF for
editing property lists. Like EDITF,
LASTWORD is used if x is NIL. EDITP
calls EDITE on the property list of
(CAR x). When (if) EDITE returns,
EDITP RPLACD's (CAR x) with the
value returned, and sets LASTWORD to
(CAR x).
The value of EDITP is the atom whose
property list was edited.
2 . 82
(EDITFNS x)
FSUBR function, used to perform the
same editing operations on several
functions. (CAR x) is evaluated to
obtain a list of functions. (CDR x)
is a list of edit commands. EDITFNS
maps down the list of functions,
prints the name of each function,
and calls the editor (via EDITF) on
that function.
For example, (EDITFNS FOOFNS (R FIE FUM)) will change
every FIE to FUM in each of the functions on FOOFNS.
The call to the editor is ERRSET
protected, so that if the editing of
one function causes an error,
EDITFNS will proceed to the next
function.
Thus in the above example, if one of the functions did
not contain a FIE, the R command would cause an error, but
editing would continue with the next function.
The value of EDITFNS is NIL
(EDIT4E pat y)
Is the pattern match routine. Its
value is T if pat matches y. See
pp. 2.22-2.23 For definition of
'match'.
Note: before each search operation in the editor
begins, the entire pattern is scanned for atoms or strings
that end in at-signs. These are replaced by patterns of the
form
(CONS (QUOTE /@) (EXPLODEC atom)).
Thus from the standpoint of EDIT4E, pattern type 5, atoms or
strings ending in at-signs, is really "If car[pat] is the
atom @ (at-sign), PAT will match with any literal atom or
string whose initial character codes (up to the @) are the
same as those in cdr[pat]."
If the user wishes to call EDIT4E directly, he must
therefore convert any patterns which contain atoms or
strings ending in at-signs to the form recgnized by EDIT4E.
This can be done via the function EDITFPAT.
2 . 83
(EDITFPAT pat flg)
Makes a copy of pat with all
patterns of type 5 converted to the
form expected by EDIT4E. Flg should
be passed as NIL (flg=T is for
internal use by the editor).
(EDITFINDP x pat flg)
Allows a program to use the edit
find command as a pure predicate
from outside the editor. X is an
expression, pat a pattern. The
value of EDITFINDP is T if the
command F pat would succeed, NIL
otherwise. EDITFINDP calls EDITFPAT
to convert pat to the form expected
by EDIT4E, unless flg=T. Thus, if
the program is applying EDITFINDP to
several different expressions using
the same pattern, it will be more
efficient to call EDITFPAT once, and
then call EDITFINDP with the
converted pattern and flg=T.
(EDITRACEFN com)
Is available to help the user debug
complex edit macros, or subroutine
calls to the editor. EDITRACEFN is
to be defined by the user. Whenever
the value of EDITRACEFN is non-NIL,
the editor calls the function
EDITRACEFN before executing each
command (at any level), giving it
that command as its argument.
For example, defineing EDITRACEFN as
(LAMBDA (C) (PRINT C) (PRINT (CAR L)))
will print each command and the corresponding current
expression. (LAMBDA (C) (BREAK1 T T NIL NIL NIL)) will
cause a break before executing each command.
EDITRACEFN is initially equal to
NIL, and undefined.
2 . 84
3.1 EXTENDED INTERPRETATION OF LISP FORMS
Extended Lambda Expressions
When solving problems in LISP, it is very often
convenient to have a function which executes more than one
form but does not need the variable and label features of
PROG. We have added this capability to UCI LISP by
extending LAMBDA expressions to handle more than one form.
(LAMBDA "ARGUMENT-LIST" "FORM1" "FORM2" . . . "FORMn")
When such a LAMBDA expression is applied to a list
of arguments each FORM is evaluated in sequence and
the value of the LAMBDA expression is FORMn (after
the arguments are bound to the LAMBDA variables).
Examples:
((LAMBDA(X) (CAR X) (CDR X)) (QUOTE (A))) = NIL
((LAMBDA(X Y) X Y (CONS X Y)) NIL T) = (NIL . T)
This means that functions defined by DF or DE
evaluate all of forms in their definition, instead
of just the first one as in Stanford's version. The
value of the function is the value of the last form.
WARNING: This is not a PROG; GO and RETURN do not have the
expected result.
3 . 1
The Functions PROG1 and PROGN
(PROG1 X1 X2 ... Xn) ,n<6
PROG1 evaluates all expressions X1 X2 ... Xn and
returns X1 as its value.
(PROGN X1 X2 ... Xn)
PROGN evaluates all expressions X1 X2 ... Xn and
returns Xn as its value.
3 . 2
Conditional Evaluation of Forms
(SELECTQ X "Y1" "Y2" ... "Yn" Z)
This very useful function is used to select a
sequence of instructions based on the value of its
first argument X. Each of the Yi is a list of the
form (Si E[1,i] E[2,i] ... E[k,i]) where Si is the
"selection key".
If Si is an atom the value of X is tested to see if
it is EQ to Si (not evaluated). If so, the
expressions E[1,i] ... E[k,i] are evaluated in
sequence, and the value of SELECTQ is the value of
the last expression evaluated, i.e. E[k,i].
If Si is a list, and if any element (not evaluated)
of Si is EQ to the value of X, then E[1,i] ...
E[k,i] are evaluated in turn as above.
If Yi is not selected in one of the two ways
described then Y[i+1] is tested, etc. until all the
Y's have been tested. If none is selected, the
value of SELECTQ is the value of Z. Z must be
present.
An example of the form of a SELECTQ is:
(SELECTQ (CAR W)
(Q (PRINT FOO) (FIE W))
((A E I O U) (VOWEL W))
(COND (W (QUOTE STOP))))
which has two cases, Q and (A E I O U) and a default
condition which is a COND.
SELECTQ compiles open, and is therefore very fast;
however, it will not work if the value of X is a
list, a large integer, or floating point number,
since it uses EQ.
3 . 3
Changes to the Handling of Errors
(ERRSET E "F")
ERRSET has been changed slightly. If F=NIL the
error message is suppressed and the error will not
cause a break to the Break Package. If F is not
given then ERRSET assumes that F=T. If F=0 (i.e.
zero) then the error message will be printed on the
current output device, otherwise it will be printed
on the teletype.
(ERR E)
There is now a special case of ERR. If the value of
E is ERRORX, then ERR will return to the most recent
ERRSET which has F=ERRORX. This allows two levels
of user errors. If a Control-G is typed in by the
user it generates a (ERR (QUOTE ERRORX)). This
means that the user can now protect himself against
this type of input error.
(ERROR E)
ERROR generates a real LISP error. E is evaluated
and printed (unless error messages are suppressed)
and then a break occurs just as for any other LISP
error.
3 . 4
Miscellania
(APPLY# FN ARGS)
APPLY# is similar to APPLY except that FN may be a
function of any type including MACRO. Note that
when either APPLY or APPLY# are given an EXPR as
their first argument, the second argument is
evaluated by APPLY# or APPLY, but the elements of
the resulting list are directly bound to the lambda
variables of the first argument, and are not
evaluated again even though it is an EXPR.
Examples:
(APPLY# (QUOTE PLUS) (QUOTE (3 2 2))) = 7
(APPLY# (QUOTE CONS) (LIST (QUOTE A) (QUOTE B))) = (A . B)
(NILL "X1" "X2" ... "Xn") = NIL
This function allows the user to stick S-Expressions
in the middle of a function definition (e.g. as a
PROG element) without having them evaluated or
otherwise noticed. NILL is also useful for giving a
dummy definition to a function which has not yet
been defined.
3 . 5
4.1 EXTENSIONS TO THE STANDARD INPUT/OUTPUT FUNCTIONS
Project-Programmer Numbers for Disk I/O
In all I/O functions (including INPUT and OUTPUT), the use
of a two element list (not a dotted pair) in place of a
device will cause the function to assume DSK: and use the
list as the project-programmer number.
Saving Function Definitions, etc. on Disk Files
(DSKOUT "FILE" "EXPRSLIST")
DSKOUT is an FEXPR and is used to create an entire
output file on disk file DSK: "FILE". It sets the
linelength to LPTLENGTH, and evaluates all of the
expressions in "EXPRSLIST". If an expression on
"EXPRSLIST" is atomic, then that atom is given to
GRINL instead of being evaluated directly.
For example, if FNLIST is a list of your functions, they can
be saved on a disk file, FUNCS.LSP by:
(DSKOUT (FUNCS.LSP) FNLIST (PRINT (QUOTE END-OF-FILE)))
Reading Files Back In
(DSKIN "LIST OF FILE-NAMES")
READ-EVAL-PRINTs the contents of the given files.
This is the function to use to read files created by
DSKOUT.
Example:
(DSKIN (FUNCS.LSP) DTA0: (DATA.LSP))
Reads FUNCS.LSP from DSK: and DATA.LSP from DTA0:.
(DSKIN (667 2) (DSKLOG.LSP))
Reads DSKLOG.LSP from the disk area of [667,2].
4 . 1
Printing Circular or Deeply Nested Lists
(PRINTLEV EXPRESSION DEPTH)
PRINTLEV is a printing routine similar to PRINT.
PRINTLEV, however, only prints to a depth of DEPTH.
In addition, PRINTLEV recognizes lists which are
circular down the CDR and closes these with '...]'
instead of ')'. The combination of these two
features allows PRINTLEV to print any circular list
without an infinite loop.
The value of PRINTLEV is the value of EXPRESSION.
This means that PRINTLEV should not be used at the
top level if EXPRESSION is a circular list
structure, since the LISP executive would then
attempt to print the circular structure which is
returned as the value.
Spacing Control
(TAB N)
TAB tabs to position N on the output line doing a
TERPRI if the current position is already past N.
Note should be taken that TAB outputs spaces only
when necessary and outputs tab characters otherwise.
4 . 2
"Pretty Printing" Function Definitions and S-Expressions
(GRINDEF "F1" "F2" "F3" ... "FN")
GRINDEF is used to print the definitions of
functions and the values of variables in a format
suitable for reading back in to LISP, in what is
known as DEFPROP format. GRINDEF uses SPRINT (see
below) to print these s-expressions in a highly
readable format, in which the levels of list
structure (or parentheses levels) are indicated by
indentation. GRINDEF prints all the properties of
the identifiers F1, F2, ..., Fn which appear on the
list GRINPROPS. If Fi is non-atomic, it will be
SPRINTed.
GRINPROPS
The variable GRINPROPS contains the properties which
will be printed by GRINDEF. This variable can be
set by the user to print special properties which he
has placed on atoms. The initial value of GRINPROPS
is (EXPR FEXPR MACRO VALUE SPECIAL).
(GRINL "F1" "F2" ... "FN")
GRINL causes all of the atoms, "F1" "F2" ... "Fn",
and all of the atoms on the lists which are the
values of the atoms F1 F2 ... Fn to be GRINDEFed.
GRINL correctly prints out read macros and is the
only function which does. GRINDEF does not save the
activation character for the read macros. Warning:
Each Fi must be an atom.
(SPRINT EXPR IND)
SPRINT is the function which does the "pretty
printing" of GRINDEF. EXPR is printed in a human
readable form, with the levels of list structure
shown by indentation along the line. This is useful
for printing large complicated structures or
function definitions. The initial indentation of
the top level list is IND-1 spaces. In normal use,
IND should be given as 1.
4 . 3
Reading Whole Lines
(LINEREAD)
LINEREAD reads a line, returning it as a list. If
some expression takes more than one line or a line
terminates in a comma, space or tab, then LINEREAD
continues reading until an expression ends at the
end of a line. This is the function used by the
EDITOR and BREAK Package supervisors to read in
commands, and may be useful for other
supervisor-type functions.
Example:
*(LINEREAD)
*A B (C D
*E) F G
(A B (C D E) F G)
*(LINEREAD)
*A B (C D E),
*F G
(A B (C D E) F G)
4 . 4
Teletype and Prompt Character Control Functions
(CLRBFI)
CLRBFI clears the Teletype input buffer.
(TTYECHO)
TTYECHO complements the Teletype echo switch. The
value of TTYECHO is T if the echo is being turned
on, and NIL if it is being turned off.
(PROMPT N)
The LISP READ routines type out a "prompt character"
for the user when they expect to read from the
teletype. This character is normally a "*". PROMPT
resets this prompt character. N is the ASCII
representation of the new prompt character.
The ASCII representation of the old prompt character
is returned as the value of PROMPT. (PROMPT NIL)
returns the current prompt character without
changing it.
Example:
*(PROMPT 53)
52
+
(INITPROMPT N)
Whenever LISP is forced back to the top level (e.g.
by an error or Control-G), the prompt character is
reset. INITPROMPT is similar to PROMPT except that
it sets the top level prompt character. (INITPROMPT
NIL) returns the ASCII value of the top level prompt
character without changing it.
4 . 5
(READP)
READP returns T if a character can be input and NIL
otherwise. READP does not input a character.
(UNTYI)
UNTYI unreads a character (such as a character input
by a TYI or a READCH) and returns the ASCII code for
that character.
Example:
*(DE PEEKC () (UNTYI (TYI)))
*(PROG () (CLRBFI) (PEEKC) (RETURN (TYI))
*A
101
4 . 5 . 1
READ MACROS - Extending the LISP READ ROUTINE
Read Macros allow the user to specify a function to be
executed each time a selected character is read during input
of his data or programs. This function is generally used to
produce one or more elements of the input list which are
built up in some way from later characters of the input
string. There are two types of Read Macros; Normal Read
Macros whose result is used as an element of the input list
in the position where the macro character occurred, and
Splice Macros whose result (must be a list which) is spliced
sequentially into the input list.
WARNING: Read macro characters will not be recognized if
they occur inside of an atom name unless the character is
first defined to be equivalent to a break or separator
character (e.g. space or comma) using MODCHR.
Functions for Defining Read Macros
(DRM "CHARACTER" "FUNCTION")
CHARACTER is defined as a Normal Read Macro with
"FUNCTION" being a function name or a LAMBDA
expression of no arguments which will be evaluated
each time CHARACTER is detected as a macro during
input. FUNCTION is put on the property list of
CHARACTER under the property READMACRO. The value
of DRM is CHARACTER.
Examples: (DRM * (LAMBDA () (NCONS (READ)))
(DRM = (LAMBDA () (REVERSE (READ)))
(DSM "CHARACTER" "FUNCTION")
DSM is exactly like DRM except that CHARACTER is
defined as a Splice Macro.
Example: (DSM : (LAMBDA () (CONS NIL (READ)))
4 . 6
Using Read Macros
The use of Read Macros is best described with examples.
The Read Macros defined above will be used for the examples.
Example 1
If the expression (A B C = (D E F) G H) is read in the
apparent input will be (A B C (F E D) G H).
Example 2
If (FOO1 FOO2 *FOO3 FOO4) is read the apparent input is
(FOO1 FOO2 (FOO3) FOO4).
In each case the associated function was evaluated and
the result was returned as the next element of the input
list.
Example 3
Reading (AT1 :(AT2 AT3) AT4) will result in
(AT1 NIL AT2 AT3 AT4).
Example 4
If the input is (AA AB :AC) the result is (AA AB NIL . AC).
It can be seen that the effect of a Splice Macro is to
place the result of the function evaluation into the input
stream minus the outermost set of parentheses.
4 . 7
Modifying the READ Control Table
Since the LISP READ routines are table driven, it is
possible to redefine the meaning of a character by changing
its table entry. In each of the following functions CH is
the ASCII representation of the character being modified.
(MODCHR CH N)
The value of MODCHR is the old table entry for CH.
If N is non-NIL it must be a number which represents
a valid table entry. The entry for CH is changed to
N. If N is NIL, no change is made, e.g. to make "."
a letter (so it will behave like the letter "A")
execute (MODCHR 56 (MODCHR 101 NIL)).
(SETCHR CH N)
SETCHR is similar to MODCHR except that it only
modifies the portion of the entry associated with
read macros.
The meaning of each of the fields in the table entry can be
determined from the descriptive diagram of the LISP READ
program in the appendix.
4 . 8
5.1 NEW FUNCTIONS ON S-EXPRESSIONS
S-Expression Building Functions
(TCONC PTR X)
TCONC is useful for building a list by adding
elements one at a time at the end. This could be
done with NCONC. However, unlike NCONC, TCONC does
not have to search to the end of the list each time
it is called. It does this by keeping a pointer to
the end of the list being assembled, and updating
this pointer after each call. The savings can be
considerable for long lists. The cost is the extra
word required for storing both the list being
assembled, and the end of the list. PTR is that
word: (CAR PTR) is the list being assembled, (CDR
PTR) is (LAST (CAR PTR)). The value of TCONC is
PTR, with the appropriate modifications to its CAR
and CDR. Note that TCONC is a destructive
operation, using RPLACA and RPLACD.
Example:
*(MAPC (FUNCTION (LAMBDA (X) (SETQ FOO (TCONC FOO X))))
(QUOTE (5 4 3 2 1)))
*FOO
((5 4 3 2 1) 1)
TCONC can be initialized in two ways. If PTR is
NIL, TCONC will make up a ptr. In this case, the
program must set some variable to the value of the
first call to TCONC. After that it is unnecessary
to reset since TCONC physically changes PTR thus:
*(SETQ FOO (TCONC NIL 1))
((1) 1)
*(MAPC (FUNCTION (LAMBDA (X) (TCONC FOO X)))
(QUOTE (4 3 2 1)))
*FOO
((1 4 3 2 1) 1)
If PTR is initially (NIL), the value of TCONC is the
same as for PTR=NIL, but TCONC changes PTR, e.g.
5 . 1
*(SETQ FOO (NCONS NIL))
(NIL)
*(MAPC (FUNCTION (LAMBDA (X) (TCONC FOO X)))
(QUOTE (5 4 3 2 1)))
*FOO
((5 4 3 2 1) 1)
The latter method allows the program to initialize,
and then call TCONC without having to perform SETQ
on its value.
(LCONC PTR X)
Where TCONC is used to add elements at the end of a
list, LCONC is used for building a list by adding
lists at the end. For example:
*(SETQ FOO (NCONS NIL))
(NIL)
*(LCONC FOO (LIST 1 2))
((1 2) 2)
*(LCONC FOO (LIST 3 4 5))
((1 2 3 4 5) 5)
*(LCONC FOO NIL)
((1 2 3 4 5) 5)
Note that LCONC uses the same pointer conventions as
TCONC for eliminating searching to the end of the
list, so that the same pointer can be given to TCONC
and LCONC interchangeably.
*(TCONC FOO NIL)
((1 2 3 4 5 NIL) NIL)
*(LCONC FOO (LIST 3 4 5))
((1 2 3 4 5 NIL 3 4 5) 5)
5 . 2
S-Expression Transforming Functions
(NTH X N)
The value of NTH is the tail of X beginning with the
Nth element, e.g. if N=2, the value is (CDR X), if
N=3, (CDDR X), etc. If N=1, the value is X, if N=0,
for consistency, the value is (CONS NIL X).
(REMOVE X L)
Removes all top level occurrences of X from the list
L, giving a COPY of L with all top level elements
EQUAL to X removed.
(COPY X)
The value of COPY is a copy of X. COPY is
equivalent to: (SUBST 0 0 X).
(LSUBST X Y Z)
Like SUBST except X is substituted as a segment.
Note that if X is NIL, LSUBST returns a copy of Z
with all Y's deleted. For example:
(LSUBST (QUOTE (A B)) (QUOTE Y) (QUOTE (X Y Z))) = (X A B Z)
5 . 3
S-Expression Modifying Functions
All these functions physically modify their arguments
by changing appropriate CAR's and CDR's.
(DREMOVE X L)
Similar to REMOVE, but uses EQ instead of EQUAL, and
actually modifies the list L when removing X, and
thus does not use any additional storage. More
efficient than REMOVE.
NOTE: If X = (L ... L) (i.e. a list of any length
all of whose top level elements are EQ to L) then
the value returned by (DREMOVE X L) is NIL, but even
after the destructive changes to X there is still
one CONS cell left in the modified list which cannot
be deleted. Thus if X is a variable and it is
possible that the result of (DREMOVE X L) might be
NIL the user must set the value of the variable
given to DREMOVE to the value returned by the
function.
(DREVERSE L)
The value of (DREVERSE L) is EQUAL to (REVERSE L),
but DREVERSE destroys the original list L and thus
does not use any additional storage. More efficient
than REVERSE.
(DSUBST X Y Z)
Similar to SUBST, but uses EQ and does not copy Z,
but changes the list structure Z itself. DSUBST
substitutes with a copy of X. More efficient than
SUBST.
5 . 4
Mapping Functions with Several Arguments
All of the map functions have been extended to allow
called functions which need more than one argument. The
function FN to be called is still the first argument.
Arguments 2 thru N (N < 7) are used as arguments 1 thru N-1
for FN. If the arguments to the map functions are of
unequal length, the map function terminates when the
shortest list becomes NIL. The functions behave the same as
the previous definitions of the functions when used with two
arguments.
Example: This will set the values of A, B and C to 1, 2 and
3, respectively.
* (MAPC (FUNCTION SET) (QUOTE (A B C)) (QUOTE (1 2 3)))
NIL
5 . 5
Mapping Functions Which Use NCONC
The functions MAPCON and MAPCAN produce lists by NCONC
to splice together the values returned by repeated
applications of their functional argument.
MAPCON and MAPCAN are especially useful in the case
where the function returns NIL. Since NIL does not affect a
list if NCONC'ed to it, the output from that function does
not appear in the result returned from MAPCON or MAPCAN.
For example, a function to remove all of the vowels from a
word can be easily written as:
(READLIST (MAPCAN (FUNCTION VOWELTEST) (EXPLODE WORD)))
where VOWELTEST is a procedure which takes one argument,
LET, and returns NIL if LET is a vowel, and (LIST LET)
otherwise.
(MAPCON FN ARG)
MAPCON calls the function FN to the list ARG. It
then takes the CDR of ARG and applies FN to it. It
continues this until ARG is NIL. The value is each
of the lists returned by FN NCONC'ed together.
For a single list MAPCON is equivalent to:
(DE MAPCON (FN ARG)
(COND ((NULL ARG) NIL)
(T (NCONC (FN ARG)
(MAPCON FN (CDR ARG))))))
Example
* (MAPCON (FUNCTION COPY) (QUOTE (1 2 3 4)))
(1 2 3 4 2 3 4 3 4 4)
(MAPCAN FN ARG)
(MAPCONC FN ARG) -- Same function by another name
MAPCAN is similar to MAPCON except it calls FN with
the CAR of ARG instead of the whole list.
5 . 6
S-Expression Searching and Substitution Functions
(SUBLIS ALST EXPR)
ALST is a list of pairs ((U1 . V1) (U2 . V2) ...
(Un . Vn)) with each Ui atomic. The value of
SUBLIS is the result of substituting each V for the
corresponding U in EXPR.
Example:
*(SUBLIS (QUOTE ((A . X) (C . Y))) (QUOTE (A B C D)))
(X B Y D)
New structure is created only if needed, e.g. if
there are no substitutions, value is EQ to EXPR.
(SUBPAIR OLD NEW EXPR)
Similar to SUBLIS except that elements of NEW are
substituted for corresponding atoms of OLD in EXPR.
Example:
*(SUBPAIR (QUOTE (A C)) (QUOTE (X Y)) (QUOTE (A B C D)))
(X B Y D)
Note: SUBLIS and SUBPAIR do not substitute copies of the
appropriate expression, but substitute the identical
structure.
(ASSOC# X Y)
Similar to ASSOC, but uses EQUAL instead of EQ.
5 . 7
(LDIFF X Y)
Y must be a tail of X, i.e. EQ to the result of
applying some number of CDRs to X. LDIFF gives a
list of all elements in X but not in Y, i.e., the
list difference of X and Y. Thus (LDIFF X (MEMB FOO
X)) gives all elements in X up to the first FOO.
Note that the value of LDIFF is always new list
structure unless Y=NIL, in which case (LDIFF X NIL)
is X itself.
If Y is not a tail of X, LDIFF generates an error.
LDIFF terminates on a NULL check.
5 . 8
Efficiently Working with Atoms as Character Strings
(FLATSIZEC L) = (LENGTH (EXPLODEC L))
(NTHCHAR X N) = (CAR (NTH (EXPLODEC L) N)) if N>0
= (CAR (NTH (REVERSE (EXPLODEC L)) N)) if N<0
= NIL if (ABS N) = 0 or > (FLATSIZEC L)
Note: The above functions do not really perform the
operations listed. They actually use far more efficient
methods that require no CONSes, but the effects are as
given.
(CHRVAL X)
CHRVAL returns the ASCII representation of the first
character of the print name of X.
5 . 9
6.1 NEW PREDICATES
Data Type Predicates
(CONSP X)
The value of CONSP is T iff X is not an atom.
CONSP is equivalent to:
(LAMBDA(X) (NOT (ATOM X)))
Examples: (CONSP T) = NIL
(CONSP 1.23) = NIL
(CONSP (QUOTE (X Y Z))) = T
(CONSP (CDR (QUOTE (X)))) = NIL
(STRINGP X)
The value of STRINGP is T iff X is a string.
(PATOM X)
The value of PATOM is T iff X is an atom or X is a
pointer outside of free storage.
(LITATOM X)
The value of LITATOM is T iff X is a literal atom,
i.e., an atom but not a number.
6 . 1
Alphabetic Ordering Predicate
(LEXORDER X Y)
The value of LEXORDER is T iff X is lexically less
than or equal to Y. Note: Both arguments must be
atoms and numeric arguments are all lexically less
than symbolic atoms.
Examples: (LEXORDER (QUOTE ABC) (QUOTE CD)) = T
(LEXORDER (QUOTE B) (QUOTE A)) = NIL
(LEXORDER 123999 (QUOTE A)) = T
(LEXORDER (QUOTE B) (QUOTE B)) = T
6 . 2
Predicates that Return Useful Non-NIL Values
(MEMBER# X Y)
MEMBER# is the same as MEMBER except that it returns
the tail of Y starting at the position where X is
found.
Examples:
(MEMBER# (QUOTE (C D)) (QUOTE ((A B)(C D)E)))
= ((C D) E)
(MEMBER# (QUOTE C) (QUOTE C))) = NIL
(MEMB X Y)
(MEMQ# X Y)
MEMQ# is the same as MEMQ except that it returns the
tail of Y starting at the position where X is found.
Examples:
(MEMQ# (QUOTE (C D)) (QUOTE ((A B)(C D)E))) = NIL
(MEMB (QUOTE A) (QUOTE (Q A B))) = (A B)
(TAILP X Y)
The value of TAILP is X iff X is a list and a tail
of Y, i.e., X is EQ to some number of CDRs & 0 of Y.
(AND# X1 X2 ... Xn) = Xn if all Xi are non-NIL
= NIL otherwise
(OR# X1 X2 ... Xn) = The first non-NIL argument
= NIL if all Xi are NIL
As with AND and OR these functions only evaluate as many of
their arguments as necessary to determine the answer (e.g.
AND# stops evaluation after the first NIL argument).
6 . 3
Other Predicates
(NEQ X Y)
The value of NEQ is T iff X is not EQ to Y.
NEQ is equivalent to:
(LAMBDA(X Y) (NOT (EQ X Y)))
Examples: (NEQ T T) = NIL
(NEQ T NIL) = T
(NEQ (QUOTE A) (QUOTE B)) = T
(NEQ 1 1.0) = T
(NEQ 1 1) = NIL
(NEQ 1.0 1.0) = T
6 . 4
7.1 NEW NUMERIC FUNCTIONS
Minimum and Maximum
(*MIN X Y) = Minimum of X and Y
(MIN X1 X2 ... Xn) = Minimum of X1, X2, ... , Xn
(*MAX X Y) = Maximum of X and Y
(MAX X1 X2 ... Xn) = Maximum of X1, X2, ... , Xn
7 . 1
FORTRAN Functions in LISP
It is now possible to use the FORTRAN Math Functions in
LISP. This allows the user to perform computations that
previously were difficult to do in LISP. All functions
return FLONUMs for values but may have either a FLONUM or a
FIXNUM for an argument.
To load the Arithmetic Package execute the following at
the top level of LISP:
*(INC(INPUT SYS: (ARITH.LSP)))
<SEQUENCE OF OUTPUT>
*(LOAD)SYS:ARITH$
<LOADER TYPES BACK>
*(ARITH)
The above will load the Arithmetic Package into
expanded core. To load the package into BINARY PROGRAM
SPACE type (LOAD T) instead of (LOAD).
Available Functions
Function Name Meaning
SIN Sine with argument in radians
SIND Sine with argument in degrees
COS Cosine with argument in radians
COSD Cosine with argument in degrees
TAN Tangent
ASIN Arc Sine
ACOS Arc Cosine
ATAN Arc Tangent
SINH Hyperbolic Sine
COSH Hyperbolic Cosine
TANH Hyperbolic Tangent
LOG Log base e
EXP Take e to a power
SQRT Square Root
FLOAT Convert to a FLONUM
RANDOM Generates a random number
between 0.0 and 1.0
7 . 2
8.1 FUNCTIONS FOR THE SYSTEM BUILDER
Loading Compiled Code into the High Segment
The UCI LISP System has a sharable high segment. This
high segment contains the interpreter, EDITOR, BREAK
package, and all of the utility functions. If the user
wants to create his own system he must be able to load
compiled code into the high segment. To allow the loading
of code into the high segment, the user must both own the
file and have write priveleges; to be write priveleged, the
user must either be creating the system from UCILSP.REL (see
the section on creating the system) or follow the procedure
indicated in the function SETSYS. The following three
functions are for the purpose of loading code into the high
segment and will only work if the user is write priveleged.
(HGHCOR X)
If X=NIL the "read-only" flag is turned on (it is
initially on) and HGHCOR returns T. Otherwise X is
the amount of space needed for compiled code. The
space is then allocated (expanding core if
necessary), the "read-only" flag is turned off and
HGHCOR returns T.
(HGHORG X)
If X=NIL the address of the first unused location is
returned as the value of HGHORG. Otherwise the
address of the first unused location is set to X and
the old value of the high seg. origin is returned.
(HGHEND)
The value of HGHEND is the address of the last
unused location in the high seg.
8 . 1
(SETSYS DEVICE FILE)
SETSYS enables the user to create his own sharable
system. DEVICE is either a project-programmer
number or a device name followed by a colon (i.e.
DSK:). FILE is the name of the system the user is
creating. In order to create the system, the user
must Control-C out and do an SSA FILE, then run the
system. After this procedure, the user has write
priveleges and may load code into the sharable high
segment. (Note that the user need not use this to
save a low segment only). This procedure is not
necessary for generating the system.
8 . 1 . 1
The Compiler and LAP
Special variables
In order to print variable bindings in the backtraces,
we have put a pointer to thje atom header in the CAR of the
SPECIAL cell of all bound atoms not used free in compiled
code. Unfortunately, for compiled code code to fun, the CAR
of the SPECIAL cell of free variables must be NIL. This,
when loading LAP code, special variables must be saved if
they are to be printed properly in a backtrace. The
necessary information is stored on LAPLST which contains the
name and the special cell of each special variable in the
system. Since this means a two word overhead for each
special variable, there is a flag which controls the adding
of items to LAPLST. Special variables are added to LAPLST
iff the variable SPECIAL is non-NIL. The initial value of
SPECIAL is T.
Removing Excess Entry Points - NOCALL Feature
If, during compilation, a function has a non-NIL NOCALL
property, all calls to that function are compiled as direct
PUSHJ's to the entry point of that function with no
reference to the atom itself. After loading, all functions
used in this manner will be left as a list on the variable
REMOB. This means that many functions which are not major
entry points can often times be REMOBed to save storage.
The user may use (NOCALL FOO1 FOO2 ... FOOn) to make
several NOCALL declarations. Like SPECIAL and DECLARE, when
NOCALL is used outside of the compiler, it acts the same an
NILL.
8 . 2
Miscellaneous Useful Functions
(UNBOUND)
UNBOUND returns the un-interned atom UNBOUND which
the system places in the CDR of an atom's SPECIAL
(VALUE) cell to indicate that the atom currently has
no assigned value even though it has a SPECIAL
(VALUE) cell on its property list.
(SYSCLR)
Re-initializes LISP to read the user's INIT.LSP file
when it returns to the top level, e.g. by a
Control-G or a START, or a REENTER.
******WARNING******:
The following two functions can catastrophically
destroy the garbage collector by creating a circle in the
free list if they are used to return to the free list any
words which are still in use. Do not use these functions
unless you are certain what you are doing. (They are only
useful in rare cases where a small amount of working storage
is needed by a routine which is called quite often.)
(FREE X)
FREE returns the word X to the free storage list and
returns NIL.
(FREELIST X)
FREELIST returns all of the words on the top level
of the list X to the free storage list and returns
NIL. FREELIST terminates on a NULL check.
8 . 3
Initial System Generation
1) To Generate UCILSP.REL
.R MACRO
*UCILSP.REL/P/P/P/P/P/P/P/P/P/P←UCILSP.MAC
(Needs to be done only when UCILSP.MAC is changed.)
2) To Generate the LISP System (LISP.SHR and LISP.LOW)
R LOADER
*UCILSP.REL$
.CORE 15
.START
BIN. PROG. SP. = 100
(INC (INPUT DSK: LAP))
<RANDOM MESSAGES>
↑C
.SSA LISP
<The preceeding loads the following files:
UCILSP.REL, LAP, SYS1.LAP, SYS2.LSP, ERRORX.LSP, ERRORX.LAP,
BREAK.LAP, EDIT.LAP>
(Needs to be done whenever any of the above files are changed.)
3) To Generate LISP.SYM, the LISP LOADER SYMBOL TABLE
.RU LO52A (Version 52 of the DEC Loader.
This file is included with the LISP System)
*UCILSP.REL/J,SYMMAK.REL$
.START
(Must be done whenever Step 1 is performed.)
8 . 4
4) To Generate COMPLR.SAV, The LISP COMPILER
.AS DSK SYS
.R LISP 36
FULL WORD SP. = 2000
BIN. PROG. SP. = 15000
*(INC (INPUT DSK: (COMPLR.LAP)))
<RANDOM MESSAGES>
*(NOUUO NIL)
*(CINIT)
↑C
.SA COMPLR.SAV
.DEL COMPLR.HGH
(Must be done whenever Step 3 is performed.)
5) To Generate LISP.LOD, the LISP LOADER
.R LOADER
*LOADER.REL$
.START
(Needs to be done only when LOADER.MAC is changed.)
8 . 5
9.1 THE LISP EVALUATION CONTEXT STACK
The Contents of the Context Stack
Whenever a form is given to EVAL, it is pushed onto
the top of the Special Pushdown List in the form of an
Eval-Blip. This information is used for backtraces. An
Eval-Blip entry has NIL in the left half (see SPDLFT) and
the form being evaluated in the right half (see SPDLRT).
Also, variable bindings are saved on the Special
Pushdown List. The left side of the entry contains a
pointer to the special cell and the right side contains
the value which was saved.
The only other items on the Special Pushdown List
are used by the LISP interpreter, and always have a
non-NIL atom in the left half.
In the user's programs, stack pointers are always
represented as INUMs. This allows the program to easily
modify them with the standard arithmetic functions so
that a program can step either up (toward the most recent
Eval-Blip) or down (toward the top level of the
interpreter) of the stack at will.
All of the functions in this chapter take INUM's for
the pointer arguments. The actual pointer to the stack
element requires an offset from the beginning of the
stack. For the user to obtain a true LISP pointer he
must call the function STKPTR (with an INUM argument
also). (i.e. if the user wishes to do an RPLACA or
RPLACD on an element of the stack, he must get a pointer
via STKPTR.)
9 . 1
Examining the Context Stack
(SPDLPT)
The value of SPDLPT is a stack pointer to the
current top of the stack. (Returns an INUM).
(SPDLFT P)
The value of SPDLFT is the left side of the stack
item pointed to by the stack pointer P.
(SPDLRT P)
The value of SPDLRT is the right side of the
stack item pointed to by the stack pointer P.
(STKPTR)
The value of STKPTR is a true LISP pointer to a
stack item.
(NEXTEV P)
If the stack pointer P is a pointer to an
Eval-Blip, the value of NEXTEV is P. Otherwise,
NEXTEV searches down the stack, starting from P,
and returns a stack pointer to the first
Eval-Blip it finds. If NEXTEV can not find an
Eval-Blip it returns NIL.
(PREVEV P)
PREVEV is similar to NEXTEV except that it moves
up the stack instead of down it.
(STKCOUNT NAME P PEND)
The value of STKCOUNT is the number of Eval-Blips
with a STKNAME of NAME occurring between stack
positions P-1 and PEND, where PEND < P.
9 . 2
(STKNAME P)
If position P is not an Eval-Blip, the value of
STKNAME is NIL. If position P is an Eval-Blip
and the form is atomic, then the value of STKNAME
is that atom. If the form is non-atomic, STKNAME
returns the CAR for the form, i.e. the name of
the function.
(STKNTH N P)
The value of STKNTH is a stack pointer to the Nth
Eval-Blip starting at position P. If N is
positive, STKNTH moves up the stack, and if N is
negative, STKNTH moves down the stack.
(STKSRCH NAME P FLAG)
The value of STKSRCH is a stack pointer to the
first Eval-Blip with a STKNAME of NAME. The
direction of the search is controlled by FLAG.
If FLAG=NIL, STKSRCH moves down the stack.
Otherwise STKSRCH moves up the stack. STKSRCH
never returns P for its value, i.e. it steps once
before checking for NAME.
(FNDBRKPT P)
The value of FNDBRKPT is a stack pointer to the
beginning of the Eval-Block that P is in. The
beginning of a Eval-Block is defined as an
Eval-Blip which does not contain the next higher
Eval-Blip within it. This function is used by
the backtrace functions.
9 . 3
Controlling Evaluation Context
(OUTVAL P V)
OUTVAL adjusts P to an Eval-Blip and returns from
that position with V.
(SPREDO P V)
SPREDO adjusts P to an Eval-Blip and re-evaluates
from that point.
(SPREVAL P V)
SPREVAL evaluates its argument v in its local
context to get a form, and then it returns to the
context specified by P and evaluates the form in
that context, returning from that context with
the value. This is very similar to SPREDO except
that the EVAL-blip on the stack is changed.
Note: OUTVAL, SPREDO and SPREVAL all use NEXTEV to adjust
P to an Eval-Blip.
(EVALV A P)
The value of EVALV is the value of the atom A
evaluated as of position P. If A is not an atom
then it must be the special cell of an atom. By
using the special cell instead of the atom,
special variables can be handled properly. EVALV
is similar to EVAL with two arguments, but is
more efficient.
(RETFROM FN VAL)
RETFROM returns VAL from the most recent call to
the function FN with the value VAL. For RETFROM
to work, there must be an Eval-Blip for FN. The
only way to be sure to get an Eval-Blip in
compiled code is to call the function with no
arguments inside of an ERRSET, e.g. (ERRSET
(FUNC)).
9 . 4
10.1 Storage Allocation
When the LISP system is run with a core
specification given (i.e., ".R LISP n", n>22), LISP types
"ALLOC? (Y OR N)". If you type "N" or space (for no)
then the system uses the current allocations. If you
type "Y" (for yes) then the system allows you to specify
for each area either an octal number followed by a space
designating the number of words to added to that area, or
a space designating an increase of zero words.
Example: (user input is underlined)
ALLOC? (Y OR N) Y
FULL WORD SP. = 200
BIN. PROG. SP. = 2000
REG. PDL. =
SPEC. PDL. = 1000
Any remaining storage is divided between the spaces as
follows:
1/16 for full word space,
1/64 for each push down list,
the remainder to free storage and bit tables.
Reallocation of Storage
If you exhaust one of the storage areas it is
possible to increase the size of that area by using the
reallocation rocedure. First, expand core with the time
sharing system command CORE and then reenter LISP with
the REE command. For example, if the original core size
was 22K, you could increase it by 4K as follows:
*↑C
.CORE 26
.REE
When you reenter LISP, the same allocation procedure is
followed as described above.
10 . 1
Initial Allocations
The following are the initial allocations for the
various storage areas when LISP is initially run.
FREE STORAGE = 2200
FULL WORD SP. = 700
BIN. PROG. SP. = 100
REG. PDL. = 1000
SPEC. PDL. = 1000
10 . 2
INDEX
A (edit command) ------------------------------ 2.13, 41
ACOS ------------------------------------------ 7. 2
AND# ------------------------------------------ 6. 3
APPLY# ---------------------------------------- 3. 5
ARGS (break command) -------------------------- 1.10
ASIN ------------------------------------------ 7. 2
ASSOC# ---------------------------------------- 5. 7
ATAN ------------------------------------------ 7. 2
B (edit command) ------------------------------ 2.13, 31
BELOW (edit command) -------------------------- 2.32, 33
BF (edit command) ----------------------------- 2.10, 28
BI (edit command) ----------------------------- 2.54
BIND (edit command) --------------------------- 2.70
BK (break command) ---------------------------- 1.15
BK (edit command) ----------------------------- 2.10, 19
BKE (break command) --------------------------- 1.15
BKF (break command) --------------------------- 1.15
BO (edit command) ----------------------------- 2.55
BREAK ----------------------------------------- 1. 1, 18
BREAKIN --------------------------------------- 1. 1, 20
BREAKMACROS ----------------------------------- 1.17
BREAK0 ---------------------------------------- 1.23
BREAK1 ---------------------------------------- 1. 6
BRKEXP ---------------------------------------- 1. 7
BROKENFNS ------------------------------------- 1.18
CHANGE (edit command) ------------------------- 2.43
CHRVAL ---------------------------------------- 5. 9
CLRBFI ---------------------------------------- 4. 5
COMS (edit command) --------------------------- 2.64
COMSQ (edit command) -------------------------- 2.64
CONSP ----------------------------------------- 6. 1
COPY ------------------------------------------ 5. 3
COS ------------------------------------------- 7. 2
COSD ------------------------------------------ 7. 2
COSH ------------------------------------------ 7. 2
DDT ------------------------------------------- 1. 5
DELETE (edit command) ------------------------- 2.14, 41, 43
DREMOVE --------------------------------------- 5. 4
DREVERSE -------------------------------------- 5. 4
DRM ------------------------------------------- 4. 6
DSKIN ----------------------------------------- 4. 1
DSKOUT ---------------------------------------- 4. 1
DSM ------------------------------------------- 4. 6
INDEX . 1
DSUBST ---------------------------------------- 5. 4
E (edit command) ------------------------------ 2. 9, 63
EDIT (break command) -------------------------- 1.13
EDIT4E ---------------------------------------- 2.83
EDITCOMSL ------------------------------------- 2.78
EDITDEFAULT ----------------------------------- 2.78
EDITE ----------------------------------------- 2.81
EDITF ----------------------------------------- 2.81
EDITFINDP ------------------------------------- 2.84
EDITFNS --------------------------------------- 2.83
EDITFPAT -------------------------------------- 2.84
EDITL ----------------------------------------- 2.80
EDITP ----------------------------------------- 2.82
EDITRACEFN ------------------------------------ 2.84
EDITV ----------------------------------------- 2.82
EMBED (edit command) -------------------------- 2.49
ERR ------------------------------------------- 3. 4
ERROR ----------------------------------------- 3. 4
ERRSET ---------------------------------------- 3. 4
EVAL (break command) -------------------------- 1. 8
EVALV ----------------------------------------- 9. 4
EX (break command)----------------------------- 1. 14
EXP ------------------------------------------- 7. 2
EXTRACT (edit command) ------------------------ 2.47
F (break command) ----------------------------- 1.11
F (edit command) ------------------------------ 2. 6, 26, 27
FLATSIZEC ------------------------------------- 5. 9
FLOAT ----------------------------------------- 7. 2
FNDBRKPT -------------------------------------- 9. 3
FREE ------------------------------------------ 8. 3
FREELIST -------------------------------------- 8. 3
FROM?= (break command) ------------------------ 1. 9, 14
FS (edit command) ----------------------------- 2.28
F= (edit command) ----------------------------- 2.28
GO (break command) ---------------------------- 1. 8
GRINDEF --------------------------------------- 4. 3
GRINL ----------------------------------------- 4. 3
GRINPROPS ------------------------------------- 4. 3
HERE (in editor) ------------------------------ 2.44, 52
HGHCOR ---------------------------------------- 8. 1
HGHEND ---------------------------------------- 8. 1
HGHORG ---------------------------------------- 8. 1
I (edit command) ------------------------------ 2.63
IF (edit command) ----------------------------- 2.66
INITPROMPT ------------------------------------ 4. 5
INSERT (edit command) ------------------------- 2.43
LAMBDA ---------------------------------------- 3. 1
LAP ------------------------------------------- 8. 2
INDEX . 2
LAPLST ---------------------------------------- 8. 2
LASTWORD -------------------------------------- 2.81, 82
LASTPOS --------------------------------------- 1.11
LC (edit command) ----------------------------- 2.31
LCL (edit command) ---------------------------- 2.31
LCONC ----------------------------------------- 5. 2
LDIFF ----------------------------------------- 5. 8
LEXORDER -------------------------------------- 6. 2
LI (edit command) ----------------------------- 2.55
LINEREAD -------------------------------------- 4. 4
LITATOM --------------------------------------- 6. 1
LO (edit command) ----------------------------- 2.55
LOG ------------------------------------------- 7. 2
LP (edit command) ----------------------------- 2.66
LPQ (edit command) ---------------------------- 2.67
LSUBST ---------------------------------------- 5. 3
M (edit command) ------------------------------ 2.68, 69
MAKEFN (edit command) ------------------------- 2.75
MAPCAN ---------------------------------------- 5. 6
MAPCON ---------------------------------------- 5. 6
MAPCONC --------------------------------------- 5. 6
MARK (edit command) --------------------------- 2.36
MAX ------------------------------------------- 7. 1
MAXLEVEL -------------------------------------- 2.24
MBD (edit command) ---------------------------- 2.14, 48
MEMB ------------------------------------------ 6. 3
MEMBER# --------------------------------------- 6. 3
MEMQ# ----------------------------------------- 6. 3
MIN ------------------------------------------- 7. 1
MODCHR ---------------------------------------- 4. 8
MOVE (edit command) --------------------------- 2.50
N (edit command) ------------------------------ 2. 5, 38
NEQ ------------------------------------------- 6. 4
NEX (edit command) ---------------------------- 2.33
NEXTEV ---------------------------------------- 9. 2
NIL (edit command) ---------------------------- 2.71
NILL ------------------------------------------ 3. 5
NOCALL ---------------------------------------- 8. 2
NTH ------------------------------------------- 5. 3
NTH (edit command) ---------------------------- 2.21, 33
NTHCHAR --------------------------------------- 5. 9
NX (edit command) ----------------------------- 2. 8, 33
OK (break command) ---------------------------- 1. 8
OK (edit command) ----------------------------- 2.71
ORF (edit command) ---------------------------- 2.28
ORR (edit command) ---------------------------- 2.67
OR# ------------------------------------------- 6. 3
OUTVAL ---------------------------------------- 9. 4
INDEX . 3
P (edit command) ------------------------------ 2. 2, 62
PATOM ----------------------------------------- 6. 1
PP (edit command) ----------------------------- 2. 2
PREVEV ---------------------------------------- 9. 2
PRINTLEV -------------------------------------- 4. 2
PROGN ----------------------------------------- 3. 2
PROG1 ----------------------------------------- 3. 2
PROMPT ---------------------------------------- 4. 5
R (edit command) ------------------------------ 2. 7, 60
RANDOM ---------------------------------------- 7. 2
READP ----------------------------------------- 4. 5. 1
REE ------------------------------------------- 1. 5
REPACK (edit command) ------------------------- 2.74
REMOVE ---------------------------------------- 5. 3
RETFROM --------------------------------------- 9. 4
RETURN (break command) ------------------------ 1. 9
RI (edit command) ----------------------------- 2.55
RO (edit command) ----------------------------- 2.56
S (edit command) ------------------------------ 2.37
SAVE (edit command) --------------------------- 2.72
SECOND (edit command) ------------------------- 2.31
SELECTQ --------------------------------------- 3. 3
SETCHR ---------------------------------------- 4. 8
SIN ------------------------------------------- 7. 2
SIND ------------------------------------------ 7. 2
SINH ------------------------------------------ 7. 2
SPECIAL --------------------------------------- 8. 2
SPDLFT ---------------------------------------- 9. 2
SPDLPT ---------------------------------------- 9. 2
SPDLRT ---------------------------------------- 9. 2
SPREDO ---------------------------------------- 9. 4
SPREVAL --------------------------------------- 9. 4
SPRINT ---------------------------------------- 4. 3
SQRT ------------------------------------------ 7. 2
STKCOUNT -------------------------------------- 9. 2
STKNAME --------------------------------------- 9. 3
STKNTH ---------------------------------------- 9. 3
STKPTR ---------------------------------------- 9. 2
STKSRCH --------------------------------------- 9. 3
STOP (edit command) --------------------------- 2.72
STRINGP --------------------------------------- 6. 1
SUBLIS ---------------------------------------- 5. 7
SUBPAIR --------------------------------------- 5. 7
SURROUND (edit command) ----------------------- 2.49
SW (edit command) ----------------------------- 2.61
SYSCLR ---------------------------------------- 8. 3
TAB ------------------------------------------- 4. 2
TAILP ----------------------------------------- 6. 3
INDEX . 4
TAN ------------------------------------------- 7. 2
TANH ------------------------------------------ 7. 2
TCONC ----------------------------------------- 5. 1
TEST (edit command) --------------------------- 2.77
THIRD (edit command) -------------------------- 2.31
THRU (edit command) --------------------------- 2.57
TO (edit command) ----------------------------- 2.57
TRACE ----------------------------------------- 1. 1, 19
TRACEDFNS ------------------------------------- 1.18
TTYECHO --------------------------------------- 4. 5
TTY: (edit command) --------------------------- 2.71
UNBLOCK (edit command) ------------------------ 2.77
UNBOUND --------------------------------------- 8. 3
UNBREAK --------------------------------------- 1.21
UNDO (edit command) --------------------------- 2.10, 76
UNDOLST --------------------------------------- 2.76, 77
UNFIND ---------------------------------------- 2.26, 36
UNTRACE --------------------------------------- 1.22
UNTYI ----------------------------------------- 4. 5. 1
UP (edit command) ----------------------------- 2.13, 16, 50
UPFINDFLG ------------------------------------- 2.45
USE (break command) --------------------------- 1.10
USERMACROS ------------------------------------ 2.70
XTR (edit command) ---------------------------- 2.14, 46
0 (edit command) ------------------------------ 2. 4, 18
*ANY* (in edit pattern) ----------------------- 2.22
*MAX ------------------------------------------ 7. 1
*MIN ------------------------------------------ 7. 1
## -------------------------------------------- 2.64
## (edit command) ----------------------------- 2.44
@ (at-sign, in edit pattern) ------------------ 2.12, 22
↑ (break command) ----------------------------- 1.10
↑ (edit command) ------------------------------ 2. 4, 18
↑↑ (break command) ---------------------------- 1.10
& (break command) ----------------------------- 1.11
& (in edit pattern) --------------------------- 2.11, 22
? (edit command) ------------------------------ 2. 2, 62
?? (edit command) ----------------------------- 2.77
?= (break command) ---------------------------- 1.13
← (in break package) -------------------------- 1.12
← (edit command) ------------------------------ 2.36
←← (edit command) ----------------------------- 2.36
: (edit command) ------------------------------ 2.14, 41
:: (edit command) ----------------------------- 2.34
::: (in edit pattern) ------------------------- 2.22
== (in edit pattern) -------------------------- 2.22
-- (in edit pattern) -------------------------- 2.11, 22
< (edit command) ------------------------------ 2.10, 36
INDEX . 5
<P (edit command) ----------------------------- 2.11, 37
(← pattern) (edit command) -------------------- 2.32
> (break command) ----------------------------- 1. 9
-> (break command) ---------------------------- 1. 9
%LOOKDPTH ------------------------------------- 1. 8
%PRINFN --------------------------------------- 1. 8
!NX (edit command) ---------------------------- 2.20
!UNDO (edit command) -------------------------- 2.76
!0 (edit command) ----------------------------- 2.18
!VALUE ---------------------------------------- 1. 8
INDEX . 6
CHANGES TO THE UCILSP SYSTEM 9/73
Summary
Various changes have again been made to the UCILSP
system. Among these are a plethora of new functions
particularly I/O type functions, access to the QMANGR to
allow spooling of output and batching of jobs. Also some
common functions such as AND and OR have been changed so
that they now return useful values instead of T. Several
new symbol table functions have been added. Internally, the
I/O has been reorganized which will make it easier for
future expansion and the bit-pushers.
A new data type has been added using binary program
space. Multiple OBLISTs are now possible using this data
type. Note that the value of the atom OBLIST is now truly
the oblist. The normal system OBLIST can be restored via a
REE when at the monitor level, followed by an ↑R
(CONTROL-R). This also often corrects that occasional
problem of a GARBAGED OBLIST. Try it and see.
Various bugs and other problems have been fixed. Some
common illegal memory references have been eliminated.
Among others, DSKOUT no longer clobbers the previously open
channel and SUBST and COPY now work properly. (They used to
be clobbered by the garbage collector).
CHANGES . 1
Changes to Old Functions
AND OR MEMQ MEMBER
These functions have been changed so that they return useful
values as did their old counterparts AND#, OR#, MEMQ# and
MEMBER#. The # functions are no longer in the system, but
are contained in a file called COMPAT.LSP.
CONSP
CONSP also returns a useful value, it's argument, if it is a
cons cell and not an atom.
DSKOUT
DSKOUT now attempts to back up the file if it already
exists.
CHANGES . 2
New I/O Functions
Various functions for file manipulation, reading
directories and queueing files have been added.
RENAME *RENAME
These functions allow the renaming of files. RENAME is an
FSUBR that does not evaluate it's arguments, *RENAME is the
SUBR version.
DELETE
DELETE is an FSUBR that deletes the files in it's argument
list. It ignores files that do not exist.
LOOKUP
LOOKUP checks to see if a file exists. Handy in conjunction
with the rename functions.
FILBAK
FILBAK renames a file to the specified extension.
QUEUE
QUEUE is the serves the same functions as the monitor
command of the same name. No longer do you have to destroy
your core image or go through the contortions of detaching
and QUEUEing to get a listing on the line printer.
UFDINP
UFDINP opens a UFD on the specified channel for reading
directories.
RDFILE
RDFILE reads the next entry from a UFD, i.e. the next file.
DIR
DIR returns a list of files in the specified directory.
RDNAM
RDNAM reads without interning.
CHANGES . 3
New Predicates
NUMTYPE
NUMTYPE returns FIXNUM or FLONUM depending on the type of
it's numeric argument.
INUMP
INUMP returns it's argument if it is an INUM and NIL
otherwise.
CHANGES . 4
Miscellaneous Functions
ERRCH
ERRCH changes the bell character that causes an (ERR (QUOTE
ERRORX)) when read. Returns the ASCII representation of the
old character. Takes the ASCII representation of the new
character as it's argument.
INITFL The system now allows a list of files instead of the old
INIT.LSP only. The first file in the list is always
optional. If any of the subsequent files are not found, an
error is generated.
*RPUTSYM RPUTSYM
Analagous to *PUTSYM and PUTSYM except that they only take
cons cells for the values. They store the values in the
symbol table with the atom relocation stripped off thus
allowing BPS to be expanded without clobbering code that
references free space.
*RGETSYM RGETSYM
Analoguos to *GETSYM and GETSYM except that the atom
relocation is add back in before returning the value.
CHANGES . 5
BLOCK Data Type
This data type is a contiguous block of storage in BINARY
PROGRAM SPACE. It's main usage is for building lists that
can also be referenced as tables. All of the functions that
work on normal lists will also work on lists built in these
BLOCKs. All of these functions return true addresses
pointing to the beginning of the BLOCK.
GTBLK
~Q↓↓↓αα≡R
dYβK↔'+K;Mε β3}≠-β?2βOS?⊗∨∃9α↓αS#O→β3}≠-β∂∞qβ↔'&C↔Iβ⊗(4)↓α↓↓β∂}sO'∪/∪↔⊃β
β3?≡Y↓β?2βC?'w#↔KMb↓β'9αβ←#'≡Aβ∂π≡)↓β'"β←'3bβ∀4R↓↓↓↓π≠∂π;v+⊃βJβS#∃ε;πK∞;∃β∂}c3↔∂&{I1β␈⊃βS#*βWO↔∩β∂π9π+O∃βO!β≠?⊂h)↓↓α↓β←#∂#↔[↔∩β#'MεC↔πK"β∪↔OO∪↔M9h(4*∀b.2N h(4)α↓↓↓α∀b.2N"β7πC~β¬β3O≠Qβ'w#=β¬∧∩2>∞Zq↓↓α&C∃α∞%⊃∨Mβ}1βS#*α
2>~βπK∀hQ↓↓↓αβ↔π∂BβOW∂≡+OO'6)β←?⊗!β?→π##∃β⊗c?∂-r↓αS#*α∞εK~βπK∃π##∃α≤
KMβ}04)↓α↓↓βSF)β3'∨!β∨'6+9βπ~β?;∃ε{→β'";Mβπ⊗;W7↔w#M9hP4(4Ph(4(hP4(4Ph(4(hP4(4Ph(4(hP4(4Ph(4(hP4(4Ph(4(hP4(4Ph(4(hP4)↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓↓↓α↓↓α∞D
:≡⊗~↓9↓XhP4(